2014-01-06 3 views
5

Так что это было задано ранее, но без удовлетворительных ответов.Rails has_one build_association удаляет запись перед сохранением

Рассмотрим две модели, User и Subscription, связанные как таковой:

class User < ActiveRecord::Base 
     has_one :subscription, dependent: :destroy 
end 

class Subscription < ActiveRecord::Base 
     belongs_to :user 
end 

Внутри из SubscriptionsController, у меня есть новое действие, которое выглядит как этот

def new 
    user = User.find(params[:user_id]) 
    @subscription = user.build_subscription 
end 

Учитывая, что подписка уже существует пользовательская запись, я столкнулся со следующей проблемой:

user.build_subscription is разрушительный, а это означает, что просто посещенияnew действие фактически разрушает ассоциацию, тем самым теряя текущую подписку на запись.

Теперь, я мог бы просто проверить существование подписки и перенаправление, как это:

def new 
    user = User.find(params[:user_id]) 
    if user.subscription.present? 
     redirect_to root_path 
    else 
     @subscription = user.build_subscription 
    end 
end 

Но это не кажется, что элегантно.

Вот мой вопрос

должен не только строить предварительной записи для ассоциации не быть разрушительными? Не нарушает ли RESTful маршрутизацию, так как new имеет доступ к запросу GET, который не должен изменить запись?

Возможно, я делаю что-то неправильно. Должен ли я строить запись по-другому? Может быть, через Subscription.new(user_id: user.id)? Кажется, не имеет большого смысла.

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

Спасибо!

ответ

2

Это зависит от того, что вы хотите сделать


Мысли

Из того, что вы в курсе, кажется, RESTful структура остается в силе для вас. Вы вызываете действие new на контроллере subscriptions, который, по определению, означает, что вы делаете новую подписку (не загружая текущую подписку)?

Вы должны помнить, что Rails - это в основном просто группа классов Ruby с методами экземпляра. Это означает, что вам не нужно, чтобы целиком RESTful структуры, если это не устраивает

Я думаю, ваша проблема в том, как вы обработки запроса/действие:

def new 
    user = User.find(params[:user_id]) 
    @subscription = user.build_subscription 
end 

@subscription строит новый объект ActiveRecord, но не обязательно должен быть таким. Вы, вероятно хотите изменить подписку (если они есть), или создать ассоциацию, если они не


Logic

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

#app/models/user.rb 
Class User < ActiveRecord::Base 

    def build 
     if subscription 
      subscription 
     else 
      build_subscription 
     end 
    end 

end 

#app/controllers/subscriptions_controller.rb 
def new 
    user = User.find(params[:user_id]) 
    @subscription = user.build 
end 

Это даст вам заполненный ActiveRecord либо с данными из подписки, либо с нового объекта ActiveRecord.


Посмотреть

В представлении, вы можете использовать поле выбора, как это:

#app/views/subscriptions/new.html.erb 
<%= form_for @subscription do |f| %> 
    <%= "User #{params[:user_id]}'s subscription: %> 
    <%= f.collection_select :subscription_id, Subscription.all,:id , :name %> 
<% end %> 

Они мои мысли, но я думаю, что вы хотите сделать что-то еще с ваш код. Если вы дадите мне несколько комментариев по этому вопросу, мы можем исправить это соответственно!

1

Я также всегда думал, что user.build_foobar будет записан только в db, если впоследствии вызывается user.save. Один вопрос: после звонка user.build_subscription, является ли старая подписка еще в базе данных?

Что такое выходные user.persisted? и user.subscription.persisted?, после звонка user.build_subscription?

Ваш метод проверки наличия подписки является ИМХО абсолютно нормально и действителен.

0

Я столкнулся с этим сегодня и согласен с тем, что удаление чего-либо из базы данных при вызове сборки - очень неожиданный результат (вызвавший у нас плохие данные). Как вы сказали, вы можете работать, если очень легко, просто используя Subscription.new (user: user). Я лично не думаю, что это гораздо менее читаемо, чем user.build_subscription.

0

По решению 2018 года Ричард Пек работал для меня:

#app/models/user.rb 
Class User < ActiveRecord::Base 

    def build_a_subscription 
     if subscription 
      subscription 
     else 
      build_subscription 
     end 
    end 
    end 

Моя проблема в том, что контроллер пользователь не имеет новый метод, так как пользователи пришли из API или из файла семян. Так что мой был похож:

#app/controllers/subscriptions_controller.rb 
def update 
    @user = User.find(params[:id]) 
    @user.build_a_subscription 
    if @user.update_attributes(user_params) 
    redirect_to edit_user_path(@user), notice: 'User was successfully updated.' 
    else 
    render :edit 
    end 
end 

И я, наконец, смог иметь правильную особую версию подписок в моем fields_for, так :subscription стихи :subscriptions

#app/views 
<%= f.fields_for :subscription do |sub| %> 
    <%= render 'subscription', f: sub %> 
<% end %> 

Прежде, чем я мог получить только fields_for, чтобы показать в представлении, если я сделал подписки множественного числа. И тогда это не спасет. Но теперь все работает.

Смежные вопросы