我想实现自定义标记功能。到目前为止,我有Item
和Tag
模型,但我很难提交标记 - 每当我尝试创建新的{{1}时,Rails就会告诉我标记分配无效 }。
(新项目的创建表示项目描述的文本区域以及来自db的所有现有标签的一系列复选框。)
奇怪地更新现有项目的标签工作正常。这一观察让我发现,罪魁祸首在于,在构建期间,item对象不会被持久化,因此它还没有Item
,因此此时无法建立项目和标记之间的关系。
基于此,我在id
中使用以下装置增强了create
操作。
虽然这样做对我来说似乎是丑陋的黑客,所以我想知道正确的方法™来处理这种情况。
ItemsController
<小时/>
class ItemsController < ApplicationController
⋮
def create
tags = {}
tags[:tag_ids] = item_params.delete('tag_ids')
reduced_params = item_params.reject{|k,v| k == 'tag_ids'}
@item = current_user.items.build(reduced_params)
@item.save
@item.update_attributes(tags)
class Item < ApplicationRecord
has_many :tag_assignments, foreign_key: 'tagged_item_id'
has_many :tags, through: :tag_assignments
⋮
class TagAssignment < ApplicationRecord
belongs_to :tagged_item, class_name: 'Item'
belongs_to :tag
⋮
items_controller.rb
class Tag < ApplicationRecord
has_many :tag_assignments
has_many :items, through: :tag_assignments
⋮
_item_form.html.erb
def create
@item = current_user.items.build(item_params)
⋮
private
def item_params
params.require(:item).permit(:description, :tag_ids => [])
end
答案 0 :(得分:1)
您可能希望使用虚拟属性,在本例中为 tag_list ,它将使用数据库中存在的新标记或已创建标记和持久标记。
class Item < ApplicationRecord
def tag_list
self.tags.collect do |tag|
tag.name
end.join(", ")
end
def tag_list=(tags_string)
tag_names = tags_string.split(",").collect{|s| s.strip.downcase}.uniq
new_or_found_tags = tag_names.collect { |name| Tag.find_or_create_by(name: name) }
self.tags = new_or_found_tags
end
现在,在您的商品表单中,您只需要引用虚拟属性而不是
<%= f.label :tag_list %><br />
<%= f.text_field :tag_list %>
这应该很简单,并且应该导致整体代码更简单。您也不要忘记相应地更改当前代码。例如,在您的项目控制器
中private
def item_params
params.require(:item).permit(:description, :tag_list)
end
现在您的项目new和创建操作可以像
一样简单def new
@item = Item.new
end
def create
@item = Item.new(item_params)
@item.save
redirect_to ......
end
答案 1 :(得分:0)
我建议使用acts_as_taggable_on gem。它解决了几乎所有关于标签使用的情况。
class User < ActiveRecord::Base
acts_as_taggable # Alias for acts_as_taggable_on :tags
acts_as_taggable_on :skills, :interests
end
class UsersController < ApplicationController
def user_params
params.require(:user).permit(:name, :tag_list) ## Rails 4 strong params usage
end
end
@user = User.new(:name => "Bobby")
@user.tag_list.add("awesome") # add a single tag. alias for <<
@user.tag_list.remove("awesome") # remove a single tag