简体   繁体   English

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

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

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.创建帖子时创建标签(帖子 has_many :tags, :through => :tag_joins.
  • A tag join is automatically created when a post is created with tags).当使用标签创建帖子时,会自动创建标签连接)。

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM