[英]How to check if a record exists before creating a new one in rails3?
Heres what I'm trying to accomplish:这是我想要完成的:
I want to check if the tag already exists.我想检查标签是否已经存在。 If it does I want to use the existing tag for the tag_join record, rather than creating a new tag record.如果确实如此,我想将现有标签用于 tag_join 记录,而不是创建新的标签记录。
Here is my current code, which isn't working.这是我当前的代码,它不起作用。
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
This doesn't work though, I'm getting an error upon task creation...(the server is actually just timing out - I don't receive a specific error).但这不起作用,我在创建任务时遇到错误......(服务器实际上只是超时 - 我没有收到特定错误)。
Any ideas?有什么想法吗?
Tokland said I was creating an infinite loop by telling it to create tag again - so I tried this: 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
And still get the server timeout并且仍然得到服务器超时
Edit: I'm not sure if this matters, but the way the tags are being added is similar to "http://railscasts.com/episodes/73-complex-forms-part-1编辑:我不确定这是否重要,但添加标签的方式类似于“http://railscasts.com/episodes/73-complex-forms-part-1
they're nested in the post form, and use something like this:它们嵌套在 post 表单中,并使用如下内容:
def tag_attributes=(tag_attributes)
tag_attributes.each do |attributes|
tags.build(attributes)
end
end
I'm wondering if this is stopping this whole thing from working?我想知道这是否会阻止这一切工作? Also, using current_user.id in the model definitely seems to be an issue...此外,在模型中使用 current_user.id 似乎肯定是一个问题......
EDIT:编辑:
Something I have figured out: this had to change, the format we were using before was incorrect syntax - generally used for a .where method.我发现了一些东西:这必须改变,我们之前使用的格式是不正确的语法 - 通常用于 .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
The problem now is this, I can learn if it the tag already exists.现在的问题是,我可以知道标签是否已经存在。 But then what?但是然后呢? If I go with the return false option, there is an error upon post creation, and the join record isn't created... The other option "self=@tag" obviously just doesn't work.如果我使用 return false 选项,则在创建后会出现错误,并且不会创建连接记录...另一个选项“self=@tag”显然不起作用。
You're going to find it hard to to this from within the Tag model.你会发现在 Tag 模型中很难做到这一点。 It seems like what you want is to update the Post using nested attributes, like so:看起来您想要的是使用嵌套属性更新 Post ,如下所示:
post = Post.create
post.update_attributes(:tags_attributes=>{"0"=>{:name=>"fish",:user_id=>"37"}})
This is actually pretty simple to do by using a virtual attribute setter method:通过使用虚拟属性设置器方法,这实际上非常简单:
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
There's a find_or_create_by_
function built right in to Rails 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 (under Dynamic attribute-based finders) http://api.rubyonrails.org/classes/ActiveRecord/Base.html (在基于动态属性的查找器下)
You want to use the magic method find_or_create_by
您想使用魔术方法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
Check out the ActiveRecord::Base docs for more info查看ActiveRecord::Base文档了解更多信息
The question I originally asked got pretty distorted by the end.我最初提出的问题到最后变得非常扭曲。 So I'm separating it.所以我要把它分开。
People who are trying to do what I originally asked can try this:试图做我最初要求的人可以试试这个:
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
This will enable you to check if your record has already been created.这将使您能够检查您的记录是否已经创建。 Any further logic you can drop in that if statment.您可以在 if 语句中加入任何进一步的逻辑。
I believe the other answers are a bit dated.我相信其他答案有点过时了。 Here's how you should probably accomplish this for Rails 4以下是您应该如何为 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
try this试试这个
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
use Tag.new
instead of Tag.create
使用Tag.new
而不是Tag.create
where 在找不到匹配项时返回一个空的 ActiveRecord。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.