While creating a bulletin board site in a Rails project, I had the opportunity to implement an image posting feature. I will leave the procedure here as a memorandum.
There are two tables, posts table
and ʻimage table. The
post_id` column of the image table has a relation to the post table.
terminal
$ rails g model Image image_url:string post:references
Open the created migration file and check it.
db/migrate/Date and time_create_images.rb
class CreateImages < ActiveRecord::Migration[5.0]
def change
create_table :images do |t|
t.string :image_url
t.references :post, foreign_key: true
t.timestamps
end
end
It seems that the migration file has been created without any problems.
terminal
$ rails db:migrate
app/model/image.rb
class Image < ApplicationRecord
belongs_to :post
end
** belongs_to: post ** is written because the references are set in the migration file.
Add ** has_many: images **.
app/models/post.rb
class Post < ApplicationRecord
has_many :images #Add this line
end
With this, we were able to express a one-to-many relationship.
This time, I will register multiple models at once with one form so that images can be posted at the same time when posting a post. What is needed for that
__ · accepts_nested_attributes_for__
is. If you use this, you will be able to register has_many related child records at once.
You will create a nested form to register the tables together. Let's use a method called accepts_nested_attributes_for to make that possible.
Now, let's set accepts_nested_attributes_for. Add the settings to the Post model as follows.
app/models/post.rb
class Post < ApplicationRecord
has_many :images
accepts_nested_attributes_for :images #Add this line
end
Add the settings to posts_controller.rb as well.
app/controllers/posts_controller.rb
class PostsController < ApplicationController
def new
@post = Post.new
@post.images.build #Add this line
end
def create
@post = current_user.posts.build(post_params)
if @post.save
flash[:success] = 'I posted a message.'
redirect_to root_url
else
@posts = current_user.feel_posts.order('created_at DESC').page(params[:page]).per(10)
flash.now[:danger] = 'Failed to post the message.'
render 'posts/new'
end
end
private
def post_params
params.require(:post).permit(:content, :security, images_attributes: [:image_url]) #Add this line
end
@post.images.build And in params images_attributes: [:image_url] Was added. The values of the parameters allowed by the nested model are described using images_attributes: in params.
erb:views/posts/new.html.erb
<%= form_for(@post) do |f| %>
<div class="form-group">
<%= f.label :content, 'comment' %>
<%= f.text_area :content, class: 'form-control', rows: 5, placeholder: 'Please enter a comment' %>
</div>
<div class="form-group">
<%= f.label :security, 'Security_Level' %>
<%= f.number_field :security, class: 'hoge', min: 0, max: 100 %>
</div>
<%= f.fields_for :images do |i| %> #Add to this line
<%= i.file_field :image_url %>
<% end %>
<div class="text-right">
<%= f.submit 'Post', class: 'btn btn-primary' %>
</div>
<% end %>
Now, you can register multiple models at once with one form. Next, create an image upload function.
Add the "Carrier Wave" gem to Gemfile.
Gemfile
gem 'carrierwave' #Image upload
Run bundle install.
terminal
$ bundle install
terminal
$ rails g uploader image
For image, set an appropriate name. This time, I named it image. When you execute the command
create app/uploaders/image_uploader.rb
And the image uploader was created.
Add the following to /models/image.rb and specify the column name in mount_uploader.
app/models/image.rb
class Image < ApplicationRecord
belongs_to :post
mount_uploader :image_url, ImageUploader #Add to this line
end
The image model has a column called image_url, which is designed to store the URL of the image.
By specifying a column in mount_uploader
, Carrierwave will automatically upload the image when updating the column and save the URL of the upload destination.
erb:view/posts/_posts.html.erb
<div>
<%= link_to post.user.name, user_path(post.user) %><span class="text-muted">posted at<% post.created_at %></span>
</div>
<div>
<p><%= post.content %></p>
</div>
<div>
<% post.images.each do |image| %>
<%= image_tag image.image_url.url %> #Show here
<% end %>
</div>
<div>
<p>Security_Level <%= post.security %></p>
</div>
<div class="batton">
<%= render 'favorites/favorite_button', post: post %>
<% if current_user == post.user %>
<%= link_to "Delete", post, method: :delete, data: { confirm: "Do you really want to delete this?" }, class: 'btn btn-danger btn-xs' %>
<% end %>
The image posting function has been implemented.
You have now implemented the image posting function in your Rails project. There are some points that can be improved, such as posting multiple images, but for the time being, it's just a paragraph.
Thank you very much.
Recommended Posts