我在使嵌套表单工作时遇到了一些问题。在下面的示例中,我有一个用户可以为帖子定义多个自定义标签。用户应该能够为每个特定标签输入值。
因此,一个帖子可以有多个标签,但每个标签只能有一个值!例如:Post可以有一个名为“Date”的标签,也有一个名为“Mood”的标签。对于两个标签,应该只有一个值。
问题是当用户创建标签-let说“日期”时 - 应该只能为此特定标签的此帖子输入一个值。因此,如果给出了日期值,则表单不应再次为日期构建另一个字段。 (帖子已有日期)
我有以下型号:
class User < ActiveRecord::Base
has_many :posts
has_many :labels
end
class Post < ActiveRecord::Base
has_many :label_values
belongs_to :user
accepts_nested_attributes_for :label_values, allow_destroy: true
end
class Label < ActiveRecord::Base
has_many :label_values
belongs_to :user
end
class LabelValue < ActiveRecord::Base
belongs_to :post
belongs_to :label
end
在我的控制器中我有
class PostsController < ApplicationController
def edit
@labels = current_user.labels.all
@post.label_values.build
end
end
我的表格:
= simple_form_for @post do |f|
=f.fields_for :label_values do |s|
=s.association :label, :include_blank => false
=s.input :value
= f.button :submit
像这样,每次用户输入特定标签的值时,下次再次构建新的label_value时,这不是我想要的。对于每个标签,用户应该能够输入一个值。
答案 0 :(得分:0)
如果您打算使用Label
将元数据附加到Post
,您可能需要考虑使用如下关系:
class User < ActiveRecord::Base
has_many :user_labels # Labels which have been used by this user.
has_many :labels, through: :user_labels
has_many :posts
end
class Post < ActiveRecord::Base
has_many :post_labels
belongs_to :user, as: :author
has_many :labels, through: :post_labels
accepts_nested_attributes_for :post_labels
def available_labels
Label.where.not(id: labels.pluck(:label_id))
end
end
class Label < ActiveRecord::Base
# @attribute name [String] The name of the label
has_many :user_labels
has_many :post_labels
has_many :users, through: :user_labels
has_many :posts, through: :post_labels
validates_uniqueness_of :name
end
# Used to store label values that are attached to a post
class PostLabel < ActiveRecord::Base
belongs_to :post
belongs_to :label
validates_uniqueness_of :label, scope: :post # only one label per post
# @attribute value [String] the value of the label attached to a post
end
# Used for something like displaying the most used labels by a user
class UserLabel < ActiveRecord::Base
belongs_to :user
belongs_to :label
end
在此设置中,标签在Stackoverflow上有点像“标签”。每个单独的标签在系统中都是唯一的,但可能会被许多用户附加到许多帖子上。
请注意validates_uniqueness_of :label, scope: :post
验证,以确保这一点。
附加到代码的实际值存储在value
的{{1}}属性中。这种方法的一个主要缺点是,您真的受到PostLabel
PostLabel
列类型的限制,可能需要进行类型转换。我真的不会像你的例子那样使用日期,因为很难根据日期进行查询。
value
这只是一些自以为是的建议:
要为帖子添加新标签,我会在已分配的标签下方添加文字输入。
我会使用def PostController
def new
@available_labels = Label.all()
end
def edit
@post = Post.joins(:labels).find(params[:id])
@available_labels = @post.available_labels
end
def create
@post = Post.new(create_params)
if (@post.save)
@post.labels.each do |l|
@post.user.labels << l
end
# ...
else
# ...
end
end
private
def create_params
params.permit(:post).allow(:post_labels)
end
end
自动填充。并过滤已存在于表单中的输入。您可以通过向GET /labels
发送ajax请求,允许用户动态创建新标签。
答案 1 :(得分:0)
我终于来了。在我创建的Post模型中:
def empty_labels
Label.where.not(:id => labelValue.select(:label_id).uniq)
end
def used_simfields
LabelValue.where(post_id: id)
end
然后在视图中我做了:
= simple_form_for @post do |f|
-@post.used_labels.each do |used_label|
=f.fields_for :label_values, used_label do |old_label|
=old_label :value
-@post.empty_labels.each do |empty_label|
=empty_label.fields_for :label_values, @post.label_values.new do |new_label|
=new_label.association :label
=new_label.input :value
我非常确定有更好的方法来实现这一点,所以非常欢迎新的想法。