【问题标题】:Adding an additional model relationships using build() on Rails在 Rails 上使用 build() 添加额外的模型关系
【发布时间】:2021-05-13 01:28:47
【问题描述】:

目前我有以下四种型号:

users <-- agency_memberships --> agencies
               |
               |
          agency_roles
       

agency_memberships 是一个连接表,agency_roles 是一个包含角色的小型查找表:

ID    NAME
-----------
1     admin
2     editor
...

在添加AgencyRole 模型之前,当创建用户时,如果参数create_agency = true,那么这足以创建一个新的Agency(沿着连接表AgencyMembership)。

# user_controller.rb

def create
  @user = User.new(user_params)
  @user.agencies.build(name: "Demo Agency") if params[:user][:create_agency]

  if @user.save!
    ...
end

但是,现在我需要在保存之前添加一个有效的AgencyRole

是否可以使用 .build() 这样做,或者 Rails 的最佳做法是什么?

现在,我在保存之前手动创建所有关系,这可行但不够紧凑:

def create
  @user = User.new(user_params)

  if (params[:user][:create_agency])

    agency_name = params[:user][:agency_name]
    agency_role = AgencyRole.find_by(name: 'admin')
    
    @agency_membership = AgencyMembership.new(agency_role: @agency_role)
    @agency = Agency.new(name: agency_name)
    
    @agency_membership.agency = @agency
    @agency_membership.user = @user
    @agency_membership.agency_role = agency_role
    
    @user.agency_memberships << @agency_membership    
  end

  if @user.save!
    ...
end

编辑:我的模特关系如下:

class AgencyMembership < ApplicationRecord
  belongs_to :agency
  belongs_to :user
  belongs_to :agency_role
end

class AgencyRole < ApplicationRecord
  validates :name, uniqueness: { case_sensitive: false }, presence: true
end

class Agency < ApplicationRecord
  has_many :agency_memberships
  has_many :projects
  has_many :users, through: :agency_memberships
end

class User < ApplicationRecord
  has_many :agency_memberships, inverse_of: :user
  has_many :agencies, through: :agency_memberships
end

【问题讨论】:

  • 您是如何在 4 个模型中声明活动记录关联的?
  • 编辑了我的答案,谢谢

标签: ruby-on-rails activerecord


【解决方案1】:

您可以将其与控制器封装分离,保留thin controller fat model,除此之外您可以使用autosave自动保存关联。

class AgencyMembership < ApplicationRecord
  belongs_to :agency_role, autosave: true
end

class Agency < ApplicationRecord
  has_one :agency_membership, autosave: true
end

module BuildAgency
  def build_with_role(attributes = {}, &block)
    agency_role_name = attributes.delete(:role)

    agency = build(attributes, &block) # association: user - membership - agency
    
    # add role    
    agency_role = AgencyRole.find_by(name: agency_role_name)
    agency.agency_membership.agency_role = agency_role # autosave

    agency
  end
end

class User < ApplicationRecord
  has_many :agencies, autosave: true, :extend => BuildAgency

  def build_agency(attributes)
   new_agency = agencies.build_with_role(attributes)
   # ...
   new_agency
  end
end

# controller
def create
  if (params[:user][:create_agency])
    @user.build_agency(name: params[:user][:agency_name], role: params[:user][:agency_role])
  end
  if @user.save! # it'll save agencies since we set `autosave`
end

【讨论】:

  • 感谢您的回答。快速提问,attributes.delete 是做什么的? agency_role_name = attributes.delete(:role)
  • @Yuan-HaoChiang 它会从attributes 哈希中提取:role,然后我们可以使用提取的值role 来构建代理角色,并且还具有有效的attributes 哈希到建立关联用户代理(因为它不再包含role)。
  • @Yuan-HaoChiang 我更新了我的答案,将提取的:role 向上移动:D
猜你喜欢
  • 2019-11-22
  • 2021-07-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-08-03
  • 1970-01-01
相关资源
最近更新 更多