Home > Net >  Ruby on Rails: How to add title input from user when uploading image
Ruby on Rails: How to add title input from user when uploading image

Time:11-17

I want to add a field to enter title when I upload an image. How and where to add the parameter in code and then show the image title above the image when uploaded?

photos_controller.rb

 class PhotosController < ApplicationController
  def create
   @user = User.find(params[:user_id])
    if params[:photo] == nil
      flash[:alert] = "Please upload a photo"
      redirect_to :back
    else
      @photo = Photo.create(photo_params)
      @photo.user_id = @user.id
      @photo.save
      flash[:notice] = "Successfully uploaded a photo"
      redirect_to user_path(@user)
    end
  end

  def new
    @user = User.find(params[:user_id])
    @photo = Photo.create()
  end

  private
  def photo_params
    params.require(:photo).permit(:image)
  end
end

photo.rb

class Photo<ActiveRecord::Base
  belongs_to :user

  has_attached_file :image, :styles => { :medium => "300x300>", :thumb => "100x100>" }, :default_url => "/images/:style/missing.png"
  validates_attachment_content_type :image, :content_type => /\Aimage\/.*\Z/
end

new.html.erb

<h1>Add a Photo</h1>
  <%= form_for Photo.new(), :url => user_photos_path, :html => {:multipart => true} do |form| %>
  <%= form.file_field :image %>
  <%= form.submit 'Upload'%>
<% end %>

show.html.erb

<%= image_tag @photo.image.url %>
<%= image_tag @photo.image.url(:thumb) %>

photos_table.rb

 class PhotosTable < ActiveRecord::Migration
   def change
     create_table :photos do |photons|
       photons.column :user_id, :integer
       photons.column :caption, :string
       photons.timestamps
     end
   end
 end

CodePudding user response:

You can add a field for :caption just like you've done with :image:

class PhotosController < ApplicationController
  ...

  def new
    @user = User.find(params[:user_id])
    @photo = Photo.new() # don't create the photo yet
  end

  private
  def photo_params
    params.require(:photo).permit(:image, :caption) # allow caption field
  end
end

new.html.erb

<h1>Add a Photo</h1>
<%= form_for Photo.new(), :url => user_photos_path, :html => {:multipart => true} do |form| %>
  <%= form.text_field :caption %>
  <%= form.file_field :image %>
  <%= form.submit 'Upload'%>
<% end %>

show.html.erb

<p><%= @photo.caption %></p>
<%= image_tag @photo.image.url %>
<%= image_tag @photo.image.url(:thumb) %>

CodePudding user response:

Your attempt is creative but it doesn't really have anything to do with how you actually do CRUD in Rails:

class User < ActiveRecord::Base
  has_many :photos
end
class PhotosController < ApplicationController

  before_action :set_user

  # POST /users/1/photos
  def create
    @photo = @user.photos.new(photo_params)
    if @photo.save
      flash[:notice] = "Successfully uploaded a photo"
      redirect_to @user
    else
      render :new
    end
  end

  # GET /users/1/photos/new
  def new
    @photo = @user.photos.new
  end

  private

  def set_user
    @user = User.find(params[:user_id])
  end

  def photo_params
    params.require(:photo)
          .permit(:image, :caption)
  end
end

You are confusing the Photo.new method which is used to initialize new instances in memory and the Photo.create method which will also save the record in the database - you don't want to do that in the new method in your controller.

if params[:photo] == nil is pointless. params.require(:photo) will raise a ActionController::ParameterMissing exception is the parameter is not present. If you want to ensure that the user has uploaded a photo or that the caption is present you use validations in your model.

What you're not checking is the one thing thats actually important - that the record is actually valid and was saved in the DB.

Use form_with instead of the older form_for which is slated for eventual deprechiation and bind the form to the model instance you create in your controller:

<h1>Add a Photo</h1>
<%= form_with model: [@user, @photo], html: { multipart: true} do |form| %>
  <div >
    <%= form.label :image %>
    <%= form.file_field :image %>
  </div>
  <div >
    <%= form.label :caption %>
    <%= form.text_field :image %>
  </div>
  <div >
    <%= form.submit 'Upload'%>
  </div>
<% end %>

That way the form will retain the user input when there is an invalid form submission. Thats why you call render :new instead of redirect_to :back. The later also doesn't actually work in case the client doesn't send a HTTP_REFERRER header (in other words don't use it).

  • Related