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).