在 Rails 上使用 build() 添加额外的模型关系
Adding an additional model relationships using build() on Rails
目前我有以下四种型号:
users <-- agency_memberships --> agencies
|
|
agency_roles
agency_memberships
是一个联接 table,agency_roles
是一个小型查找 table,角色为:
ID NAME
-----------
1 admin
2 editor
...
在添加AgencyRole
模型之前,创建用户时,如果参数create_agency = true
,那么这足以创建一个新的Agency
(沿着连接table 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
你可以把它封装起来和controller分开,保留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
目前我有以下四种型号:
users <-- agency_memberships --> agencies
|
|
agency_roles
agency_memberships
是一个联接 table,agency_roles
是一个小型查找 table,角色为:
ID NAME
-----------
1 admin
2 editor
...
在添加AgencyRole
模型之前,创建用户时,如果参数create_agency = true
,那么这足以创建一个新的Agency
(沿着连接table 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
你可以把它封装起来和controller分开,保留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