Как проверить, существует ли запись перед созданием новой в rails3? - PullRequest
5 голосов
/ 12 февраля 2011

Вот что я пытаюсь сделать:

  • У меня есть система тегов.
  • Теги создаются при создании сообщений (posts has_many: tags,: through =>: tag_joins.
  • Соединение тегов создается автоматически при создании сообщения с тегами).

Я хочу проверить, существует ли тег уже. Если это так, я хочу использовать существующий тег для записи 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

Хотя это не работает, я получаю сообщение об ошибке при создании задачи ... (на самом деле сервер просто перестал работать - я не получаю конкретной ошибки).

Есть идеи?

Токланд сказал, что я создаю бесконечный цикл, сказав ему снова создать тег - поэтому я попробовал это:

 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 в модели определенно является проблемой ...

EDIT:

Что-то, что я понял: это должно было измениться, формат, который мы использовали прежде, был неправильным синтаксисом - обычно используемый для метода .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", очевидно, просто не работает.

Ответы [ 7 ]

12 голосов
/ 13 февраля 2011

Тебе будет трудно это из-за модели Tag.Похоже, что вы хотите обновить сообщение, используя вложенные атрибуты, например:

post = Post.create
post.update_attributes(:tags_attributes=>{"0"=>{:name=>"fish",:user_id=>"37"}})

Это на самом деле довольно просто сделать с помощью метода установки виртуальных атрибутов:

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
9 голосов
/ 12 февраля 2011

Есть функция 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 (в разделе Динамические искатели на основе атрибутов)

6 голосов
/ 12 февраля 2011

Вы хотите использовать магический метод 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 для получения дополнительной информации

4 голосов
/ 13 февраля 2011

Вопрос, который я первоначально задал, к концу довольно исказился. Так что я это разделяю.

Люди, которые пытаются сделать то, что я изначально просил, могут попробовать это:

 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

Это позволит вам проверить, была ли ваша запись уже создана. Любую дальнейшую логику вы можете оставить в этом, если заявите.

3 голосов
/ 28 марта 2013

Я думаю, что другие ответы немного устарели. Вот как вы, вероятно, должны выполнить это для 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
0 голосов
/ 01 марта 2013

где возвращает пустую ActiveRecord при обнаружении совпадения.

0 голосов
/ 12 февраля 2011

попробуйте

  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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...