我有一个相当简单的问题,但我想不出简单的解决方案。我有3个型号。
class User < ActiveRecord::Base
has_many :memberships
end
class Membership < ActiveRecord::Base
belongs_to :user
belongs_to :school
end
class School < ActiveRecord::Base
has_many :memberships
end
用户可以为学校创建会员资格。 “会员编号”由学校提供。到现在为止还挺好。
除了一个用例,其中成员资格记录由学校创建,而成员资格表中没有user_id值。
在这种情况下,使用“membernumber”,“school_id”和空“user_id”字段创建记录。
我想要做的是,当用户试图在学校创建他的会员资格(使用他的“会员编号”)时,首先我要查看“user_id”,“membernumber”。如果找到,school_id组合是唯一的(我使用了validates_uniqueness_of ....)。
如果找不到记录,则检查与“membernumber”的记录/关联,并且学校存在并且其user_id字段为空。如果是这种情况,那么不要创建新的成员资格,只需更新它的user_id字段(使用current_user.id),并使用msg返回新关联的创建成功(就好像它是一个新的成员资格记录)。
我该怎么做?我需要使用任何回调吗?在这种情况下如何使用回调? 任何帮助表示赞赏。
谢谢,
Atarangp
答案 0 :(得分:3)
你也应该在你的迁移中强制执行唯一性限制,不管多少DHH都会在整个过程中宣传“愚蠢的持久性”,并且只在应用层面处理这个问题。
最简单的方法是在validates_presence_of :user_id
模型中强制执行Membership
。如果用户ID不存在,则不允许创建连接记录;无论如何,您的AR关联查询应该固有地传递此ID。
例如,请考虑 - User.last.memberships.build(@school)
,并且在您的应用程序的上下文中,用户将是current_user
本身。
before_create
和其他before_
AR回调绝对是方便的,但我总是将这种方法作为最后的手段。原因是你直觉地期望你的应用程序以某种方式运行,而这些before_
回调可以实质上改变命中数据库的信息。当然,单元测试会处理这些问题。
答案 1 :(得分:1)
只有通过模型才能看出:
has_and_belongs_to_many
或has_many :through
关系的联接表如果上述方法适用于您,那么您的模型应如下所示:
class User < ActiveRecord::Base
has_many :memberships
has_many :schools, :through => :memberships
end
class Membership < ActiveRecord::Base
belongs_to :user
belongs_to :school
end
class School < ActiveRecord::Base
has_many :memberships
has_many :users, :through => :memberships
end
现在,您应该可以将用户添加到学校,反之亦然。
user = User.first
user.schools << School.first
这会自动在会员资格中创建一个带有适当引用的记录。并且用户将开始在School.first.users
中显示。此外,您可以在school_id范围内添加唯一性验证,即validates_uniqueness_of :user_id, :scope => :school_id
。
before_ after_回调很好,但在这种情况下,您需要一些自定义代码来保持同步。以上将消除对before_ after_回调的任何依赖。此外,您不需要为会员模型上的任何其他验证检查而烦恼,因为只有当用户记录添加到学校记录时才会自动创建记录,反之亦然。
答案 2 :(得分:0)
这就是我解决它的方法 在模型成员资格中,添加了一个方法membership membership,并从成员资格的create中调用它 行动。
class Membership < ActiveRecord::Base
belongs_to :school
belongs_to :user
#validations, etc.
def Membership.membership_exists(membernumber, school_id)
membership = Membership.where(:membernumber => membernumber, :school_id => school_id, :user_id => nil).first
if membership.nil?
return false
else
membership.update_attribute :user_id, user_id
return true
end
end
end
在会员控制器中(在创建操作中)
def create
@membership = Membership.new(params[:membership])
@membership.user_id = current_user.id
@flag = Membership.membership_exists(@membership.membernumber,@membership.school_id)
if @flag == true
flash[:notice] = "Membership creation is successful"
redirect_to @membership
return
end
respond_to do |format|
if @membership.save
format.html { redirect_to @membership, notice: 'Membership was successfully created.' }
format.json { render json: @membership, status: :created, location: @membership }
else
format.html { render action: "new" }
format.json { render json: @membership.errors, status: :unprocessable_entity }
end
end
end
这很有效。但这是一个很好的方法吗?
谢谢, Atarangp。