I am making an app that imitates Instagram. As shown below, there is a post linked to the user, and it has a structure that has multiple images.
It was nice to have created a new post form using form object
with this structure,
▼ Implemented in this article The story of saving an image with carrierwave in a nested form using a form object.
From there, I had a lot of trouble creating the update
form, so I'll put together the code I wrote.
The execution environment is as follows.
Rails 5.2.3
Ruby 2.6.0
Also, I use carrier wave
to post images.
I will introduce the code I actually wrote and add an explanation to it.
controller
The instance created by form object
is passed to the view in the form of @post_form.
controllers/posts_controller.rb
class PostsController < ApplicationController
before_action :require_login, only: %i(new edit)
before_action :set_post, only: %i(edit update)
def new
@post_form = PostForm.new(current_user)
end
def create
@post_form = PostForm.new(current_user, post_params, post: Post.new)
if @post_form.save!
redirect_to root_path
flash[:success] = "Posted"
else
flash.now[:danger] = "Posting failed"
render :new
end
end
def edit
@post_form = PostForm.new(current_user, post: @post)
end
def update
@post_form = PostForm.new(current_user, post_params, post: @post)
if @post_form.save!
redirect_to root_path
flash[:success] = "I edited the post"
else
flash.now[:danger] = "Post edit failed"
render :edit
end
end
private
def post_params
params.require(:post).permit(:body, photoes: [])
end
def set_post
@post = Post.find(params[:id])
end
end
view
The view receives an instance in the form model: @post_form
. (Actually, the same partial was used for new
and edit
, so @ post_form
was made a local variable called form
.)
Ruby:views/posts/_post_form.html.slim
= form_with model: @post_form, local: true do |f|
.form-group
= f.label :photoes, t('activerecord.models.images.photo'), class: 'bmd-label-floating"'
= f.file_field :photoes, multiple: true, class: 'form-control mb-1'
.form-group
= f.label :body, t('activerecord.models.posts.body'), class: 'bmd-label-floating"'
= f.text_field :body, class: 'form-control'
= f.submit 'register', class: 'btn btn-raised btn-success'
form object
forms/post_form.rb
class PostForm
include ActiveModel::Model
attr_accessor :body, :photoes, :user
validates :body, presence: true
def initialize(user, params = {}, post: '')
@post ||= Post.new
@post.assign_attributes({user: user, body: params[:body]})
super(params)
end
def to_model #I will explain
@post
end
def save!
return false if invalid?
if photoes
photoes.each do |photo|
@post.images.build(photo: photo).save!
end
end
@post.save! ? true : false
end
end
The point is that to_model
makes the form object
behave like a model. What this means is that the form object
is a" just class "different from the ActiveRecord model, so the routing path that Rails guesses by default on new / edit forms is applied well. not.
So by making to_model
think of form object
as if it were a model, Rails' default routing can be used with form object
as well.
The implementation around here was very helpful to this article.
Rails: Separate validation from model using Form Object and # to_model
(translation)
However, even with this implementation, for the update
action, I tried to access POST'posts /: id'
and did not follow the routing well.
On the other hand, I was able to find the following two solutions on the net.
-Overwrite the URL of form
.
-Change the action to apply using delegate
.
In my case, the former was too verbose in code and the latter couldn't work well, so I had no choice but to rewrite routes.rb
as follows.
config/routes.rb
post '/posts/:id', to: 'posts#update'
I can't deny the feeling of a monkey patch, but this time I'm happy with this ... I would like to refactor it when my ability improves a little more.
In my work implementation, the update method of the form object
didn't take the time to implement it and gave up, but now I have a clue for the implementation: relaxed:
I want to improve my knowledge so that I can share it within the company: sparkles:
Recommended Posts