这是我想要完成的事情:
我想检查标签是否已存在。如果是的话,我想使用tag_join记录的现有标签,而不是创建新的标签记录。
这是我当前的代码,但无效。
class Tag < ActiveRecord :: Base
belongs_to :user
belongs_to :tag_join
belongs_to :post
before_create :check_exists
def check_exists
tag = Tag.where(:name => self.name, :user_id => current_user.id)
if tag.nil?
tag = Tag.create(:name => self.name, :user_id => current_user.id)
end
end
end
这不起作用,我在创建任务时遇到错误...(服务器实际上只是超时 - 我没有收到特定错误)。
有什么想法吗?
Tokland说我通过告诉它再次创建标签来创建一个无限循环 - 所以我尝试了这个:
def check_exists
tag = Tag.find_by_name_and_user_id(:name => self.name, :user_id => current_user.id)
if tag != nil
self.id = tag.id
end
end
仍然可以获得服务器超时
编辑:我不确定这是否重要,但标签的添加方式类似于“http://railscasts.com/episodes/73-complex-forms-part-1
它们嵌套在帖子中,并使用类似的东西:
def tag_attributes=(tag_attributes)
tag_attributes.each do |attributes|
tags.build(attributes)
end
end
我想知道这是否会阻止整件事工作?此外,在模型中使用current_user.id肯定似乎是一个问题......
修改
我发现了一些事情: 这必须改变,我们以前使用的格式是不正确的语法 - 通常用于.where方法。
def check_exists
@tag = Tag.find_by_name_and_user_id(self.name, self.user_id)
if @tag != nil
#return false
#self=@tag
end
end
现在的问题是,我可以了解标签是否已经存在。但那又怎样?如果我使用return false选项,则在创建帖子时会出现错误,并且不会创建连接记录...其他选项“self = @ tag”显然不起作用。
答案 0 :(得分:12)
您将很难从Tag模型中找到它。看起来你想要的是使用嵌套属性更新Post,如下所示:
post = Post.create
post.update_attributes(:tags_attributes=>{"0"=>{:name=>"fish",:user_id=>"37"}})
使用虚拟属性setter方法实际上很简单:
class Post < AR::Base
has_many :tags
def tags_attributes=(hash)
hash.each do |sequence,tag_values|
tags << Tag.find_or_create_by_name_and_user_id(tag_values[:name],\
tag_values[:user_id])
end
end
> post = Post.create
> post.update_attributes(:tags_attributes=>{"0"=>{:name=>"fish",:user_id=>"37"}})
> Tag.count # => 1
# updating again does not add dups
> post.update_attributes(:tags_attributes=>{"0"=>{:name=>"fish",:user_id=>"37"}})
> Tag.count # => 1
答案 1 :(得分:9)
Rails中内置了一个find_or_create_by_
函数
# No 'Summer' tag exists
Tag.find_or_create_by_name("Summer") # equal to Tag.create(:name => "Summer")
# Now the 'Summer' tag does exist
Tag.find_or_create_by_name("Summer") # equal to Tag.find_by_name("Summer")
http://api.rubyonrails.org/classes/ActiveRecord/Base.html(在基于动态属性的查找器下)
答案 2 :(得分:6)
您想要使用魔术方法find_or_create_by
def check_exists
tag = Tag.find_or_create_by_name_and_user_id(:name => self.name, :user_id => current_user.id)
end
查看ActiveRecord::Base文档以获取更多信息
答案 3 :(得分:4)
我最初提出的问题在结尾时变得非常扭曲。所以我把它分开了。
试图做我最初要求的人可以试试这个:
before_create :check_tag exists
private
def check_tag_exists
@tag = Tag.find_by_name_and_user_id(self.name, self.user_id)
if @tag != nil
#
end
end
这将使您能够检查您的记录是否已创建。如果是法定的话,你可以放下任何进一步的逻辑。
答案 4 :(得分:3)
我相信其他答案有点陈旧。以下是你应该如何为Rails 4实现这个目标
tag = Tag.first_or_initialize(:name => self.name, :user_id => current_user.id)
if !tag.new_record?
tag.id = self.id
tag.save
end
答案 5 :(得分:0)
试试这个
def check_exists
tag = Tag.where(:name => self.name, :user_id => current_user.id).first
tag = Tag.new({:name => self.name, :user_id => current_user.id}) unless tag
end
使用Tag.new
代替Tag.create
答案 6 :(得分:-2)
其中返回空的ActiveRecord,找不到匹配项。