Подтвердить что ты не робот

В Rails лучший способ обновить запись или создать новую, если она не существует?

У меня есть оператор create для некоторых моделей, но он создает запись в таблице соединений, независимо от того, существует ли запись.

Вот как выглядит мой код:

@user = User.find(current_user)
@event = Event.find(params[:id])
for interest in @event.interests
 @user.choices.create(:interest => interest, :score => 4)
end

Проблема в том, что он создает записи независимо от того, что. Я хотел бы, чтобы он создал запись только в том случае, если запись уже не существует; если запись существует, я бы хотел, чтобы она взяла атрибут найденной записи и добавила или вычитала 1.

Я смотрю вокруг, увидел что-то, называемое find_or_create_by. Что это делает, когда он находит запись? Я бы хотел, чтобы он взял текущий атрибут :score и добавил 1.

Можно ли найти или создать id? Я не уверен, какой атрибут я найду, поскольку модель Im look at - это модель объединения, которая имеет только id внешние ключи и атрибут оценки.

Я пробовал

@user.choices.find_or_create_by_user(:user => @user.id, :interest => interest, :score => 4)

но получил

undefined метод find_by_user

Что мне делать?

4b9b3361

Ответ 1

Предполагая, что модель Choice имеет user_id (для связи с пользователем) и interest_id (для связи с интересом), что-то вроде этого должно сделать трюк:

@user = User.find(current_user)
@event = Event.find(params[:id])

@event.interests.each do |interest|
  choice = @user.choices.find_or_initialize_by_interest_id(interest.id) do |c|
    c.score = 0 # Or whatever you want the initial value to be - 1
  end

  choice.score += 1
  choice.save!
end

Некоторые примечания:

  • Вам не нужно включать столбец user_id в find_or_*_by_*, поскольку вы уже указали Rails только на выбор choices, принадлежащий @user.
  • Я использую find_or_initialize_by_*, который по существу те же, что и find_or_create_by_*, причем одним ключевым отличием является то, что initialize фактически не создает запись. Это было бы похоже на Model.new в отличие от Model.create.
  • Блок, который устанавливает c.score = 0, выполняется только в том случае, если запись не существует.
  • choice.score += 1 обновит значение оценки для записи, независимо от того, существует ли она или нет. Следовательно, значением по умолчанию c.score = 0 должно быть начальное значение минус единица.
  • Наконец, choice.save! либо обновит запись (если она уже существует), либо создаст начальную запись (если это не так).

Ответ 2

my_class = ClassName.find_or_initialize_by_name(name)

my_class.update_attributes({
   :street_address => self.street_address,
   :city_name => self.city_name,
   :zip_code => self.zip_code
})

Ответ 3

find_or_create_by_user_id звучит лучше

Ответ 4

Кроме того, в Rails 3 вы можете:

@user.choices.where(:user => @user.id, :interest => interest, :score => 4).first_or_create

Ответ 5

Если вы используете рельсы 4, я не думаю, что он создает методы поиска, как это было раньше, поэтому find_or_create_by_user не создан для вас. Вместо этого вы сделаете это следующим образом:

@user = User.find(current_user)
@event = Event.find(params[:id])
for interest in @event.interests
 @user.choices.find_or_create_by(:interest => interest) do |c|
  c.score ||= 0
  c.score += 1
 end
end

Ответ 6

В Rails 4 Вы можете использовать find_or_create_by для получения объекта (если не существует, он будет создан), а затем использовать update для сохранения или обновления записи, метод обновления будет сохранять запись, если она не существует, иначе запись обновления.

Например

@edu = current_user.member_edu_basics.find_or_create_by(params.require(:member).permit(:school))

if @edu.update(params.require(:member).permit(:school, :majoy, :started, :ended))