Ruby-on-rails 在rails3中创建新记录之前如何检查记录是否存在?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4978893/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-03 00:24:17  来源:igfitidea点击:

How to check if a record exists before creating a new one in rails3?

ruby-on-railsruby-on-rails-3

提问by Elliot

Heres what I'm trying to accomplish:

这是我想要完成的:

  • I have a tagging system in place.
  • Tags are created, when Posts are created (posts has_many :tags, :through => :tag_joins.
  • A tag join is automatically created when a post is created with tags).
  • 我有一个标记系统。
  • 创建帖子时创建标签(帖子 has_many :tags, :through => :tag_joins.
  • 使用标签创建帖子时,会自动创建标签连接)。

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”显然不起作用。

回答by zetetic

You're going to find it hard to to this from within the Tag model. It seems like what you want is to update the Post using nested attributes, like so:

你会发现在 Tag 模型中很难做到这一点。看起来您想要的是使用嵌套属性更新 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

回答by Bjorn

There's a find_or_create_by_function built right in to Rails

find_or_create_by_Rails 内置了一个函数

# 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(在基于动态属性的查找器下)

回答by Rob Di Marco

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::Basedocs for more info

查看ActiveRecord::Base文档了解更多信息

回答by Elliot

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 语句中加入任何进一步的逻辑。

回答by sarink

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

回答by rubyprince

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.newinstead of Tag.create

使用Tag.new代替Tag.create

回答by Peter Zensius

where returns an empty ActiveRecord on finding no match.

where 在找不到匹配项时返回一个空的 ActiveRecord。