A story about how I got hooked on the combination of Rails Virtual Attributes and Nested Attributes

8

It took a long time to solve the problem, so I will leave it as a memoir. When I did registration / update processing with the following model, the before_validation of the user model was not called, and I was addicted because I did not know the cause.

app/models/team.rb
class Team < ApplicationRecord
  has_many :users

  accepts_nested_attributes_for :users, allow_destroy: true
end
app/models/user.rb
class User < ApplicationRecord
  belongs_to :team

  attr_writer :first_name, :last_name

  before_validation :set_name

  private

  def set_name
    self.name = "#{@last_name} #{@first_name}"
  end
end

By the way, the implementation of the controller is as follows.

app/controllers/teams_controller.rb
class TeamsController < ApplicationController
  # ...

  def create
    @team = Team.new(team_params)

    return render(:new) if @team.invalid?

    @team.save!
  end

  def update
    @team = Team.find(params[:id])
    @team.attributes = team_params

    return render(:edit) if @team.invalid?

    @team.save!
  end

  private

  def team_params
    params
      .require(:team)
      .permit(:name, :logo, users_attributes: [:id, :_destroy, :first_name, :last_name, :gender, :birthday])
  end
end

In conclusion, changes in Virtual Attributes cannot be detected in the changed? of the model, so when only Virtual Attributes are updated, it becomes changed? == false and validation is not performed. When validates_associated is added to the parent model as shown below, validation is always performed on the specified child model.

app/models/team.rb
class Team < ApplicationRecord
  has_many :users

  accepts_nested_attributes_for :users, allow_destroy: true

  # 追加
  validates_associated :users
end
Share:
8
Author by

Updated on March 06, 2018