[RAILS] Story of implementing update function in form object

What did you do

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.

Image from Gyazo

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.

Also, I use carrier wave to post images.

Code I wrote

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)

[Unresolved] The issue that was occurring in the uodate action.

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.

Impressions etc.

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

Story of implementing update function in form object
Implement tagging function in form object
Story of implementing login function using gem sorcery
Implementation of like function in Java
The story of AppClip support in Anyca
Immutable (immutable) List object conversion function in Java8
The story of writing Java in Emacs
A story about saving an image with carrierwave in a nested form using a form object.
The story of low-level string comparison in Java
The story of making ordinary Othello in Java
The story of learning Java in the first programming
[Rails] Implementation of retweet function in SNS application
Write a test by implementing the story of Mr. Nabeats in the world with ruby
The story of an Illegal State Exception in Jetty.
[Rilas] What I learned in implementing the pagination function.
Consideration of options for implementing native apps (in writing)