Rails 有很多通过关联设置多个属性
Rails has many through association setting multiple attributes
所以我有一个 has_many through
关联,其中两个 tables posts
和 users
:
class Post < ApplicationRecord
has_many :assignments
has_many :users, :through => :assignments
end
class User < ApplicationRecord
has_many :assignments
has_many :posts, :through => :assignments
end
class Assignment < ApplicationRecord
belongs_to :request
belongs_to :user
end
现在在我的协会 table (assignment
) 中有 creator:boolean
和 editor:boolean
的附加属性。
我的问题是从控制器内部设置这些次要属性的最佳方式是什么?
环顾四周,我找到了当前的解决方案:
posts_controller.rb
:
class PostsController < ApplicationController
def create
params.permit!
@post = Post.new(post_params)
if @post.save
Assignment.handle_post(@post.id, params[:creator], params[:editors])
redirect_to posts_path, notice: "The post #{@post.title} has been created."
else
render "new"
end
end
assignment.rb
:
class Assignment < ApplicationRecord
belongs_to :request
belongs_to :user
def self.handle_post(post_id, creator, assignment)
Assignment.where(:post_id => post_id).delete_all
Assignment.create!(:post_id => post_id, :user_id => creator, :creator => true, :editor => false)
if editors.present?
editors.each do |e|
Assignment.create!(:post_id => post_id, :user_id => e, :creator => false, :editor => true)
end
end
end
end
所以实际上发生的事情是我通过 params
(creator
returns 1 id, editors
returns 一个数组),在创建 post 之后,我将删除与 post 关联的所有列,并根据新属性重新创建它们。
我遇到的问题是我无法 运行 post
对这些关联进行验证(例如检查创建者是否存在)。
我的两个问题如下:
- 这是处理次要属性的正确方法吗?
- 有没有一种方法可以设置关联然后一次性保存所有关联以便执行验证?
这是一种更 Rails 的方法:
使用嵌套属性
post.rb
class Post < ApplicationRecord
# Associations
has_many :assignments, inverse_of: :post
has_many :users, through: :assignments
accepts_nested_attributes_for :assignments
# Your logic
end
assignment.rb
class Assignment < ApplicationRecord
after_create :set_editors
belongs_to :request
belongs_to :user
belongs_to :post, inverse_of: :assignments
# I would create attribute accessors to handle the values passed to the model
attr_accessor :editors
# Your validations go here
validates :user_id, presence: true
# Your logic
private
def set_editors
# you can perform deeper vaidation here for the editors attribute
if editors.present?
editors.each do |e|
Assignment.create!(post_id: post_id, user_id: e, creator: false, editor: true)
end
end
end
end
最后,将其添加到您的 PostsController
params.require(:post).permit(..., assignments_attributes: [...])
这允许您从创建 Post 操作创建作业,运行 验证 Post 和作业以及 运行 回调。
希望对您有所帮助!
所以我有一个 has_many through
关联,其中两个 tables posts
和 users
:
class Post < ApplicationRecord
has_many :assignments
has_many :users, :through => :assignments
end
class User < ApplicationRecord
has_many :assignments
has_many :posts, :through => :assignments
end
class Assignment < ApplicationRecord
belongs_to :request
belongs_to :user
end
现在在我的协会 table (assignment
) 中有 creator:boolean
和 editor:boolean
的附加属性。
我的问题是从控制器内部设置这些次要属性的最佳方式是什么?
环顾四周,我找到了当前的解决方案:
posts_controller.rb
:
class PostsController < ApplicationController
def create
params.permit!
@post = Post.new(post_params)
if @post.save
Assignment.handle_post(@post.id, params[:creator], params[:editors])
redirect_to posts_path, notice: "The post #{@post.title} has been created."
else
render "new"
end
end
assignment.rb
:
class Assignment < ApplicationRecord
belongs_to :request
belongs_to :user
def self.handle_post(post_id, creator, assignment)
Assignment.where(:post_id => post_id).delete_all
Assignment.create!(:post_id => post_id, :user_id => creator, :creator => true, :editor => false)
if editors.present?
editors.each do |e|
Assignment.create!(:post_id => post_id, :user_id => e, :creator => false, :editor => true)
end
end
end
end
所以实际上发生的事情是我通过 params
(creator
returns 1 id, editors
returns 一个数组),在创建 post 之后,我将删除与 post 关联的所有列,并根据新属性重新创建它们。
我遇到的问题是我无法 运行 post
对这些关联进行验证(例如检查创建者是否存在)。
我的两个问题如下:
- 这是处理次要属性的正确方法吗?
- 有没有一种方法可以设置关联然后一次性保存所有关联以便执行验证?
这是一种更 Rails 的方法:
使用嵌套属性
post.rb
class Post < ApplicationRecord
# Associations
has_many :assignments, inverse_of: :post
has_many :users, through: :assignments
accepts_nested_attributes_for :assignments
# Your logic
end
assignment.rb
class Assignment < ApplicationRecord
after_create :set_editors
belongs_to :request
belongs_to :user
belongs_to :post, inverse_of: :assignments
# I would create attribute accessors to handle the values passed to the model
attr_accessor :editors
# Your validations go here
validates :user_id, presence: true
# Your logic
private
def set_editors
# you can perform deeper vaidation here for the editors attribute
if editors.present?
editors.each do |e|
Assignment.create!(post_id: post_id, user_id: e, creator: false, editor: true)
end
end
end
end
最后,将其添加到您的 PostsController
params.require(:post).permit(..., assignments_attributes: [...])
这允许您从创建 Post 操作创建作业,运行 验证 Post 和作业以及 运行 回调。
希望对您有所帮助!