2014-01-06 13 views
5

これは前に尋ねられましたが、満足のいく回答はありません。Rails has_one build_associationは保存する前にレコードを削除します

は二つのモデル、User、そのように関連付けられているSubscription考えてみましょう:SubscriptionsControllerの内部

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

class Subscription < ActiveRecord::Base 
     belongs_to :user 
end 

を、私はサブスクリプションがすでに存在することを考えると、この

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

のように見える新しいアクションを持っていますユーザーレコード、私は次の問題に直面しています:

user.build_subscriptionはです単にを訪問newアクションが実際に関連し、それによって現在のサブスクリプションレコードを失うことを破壊することを意味破壊 、。

今、私は単純に、サブスクリプションの存在をチェックし、次のようにリダイレクトすることができます:

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

しかし、それはすべてのことがエレガントないないようです。

は、ここに私の質問

はちょうど協会ためレコードが破壊的でない建物べきではないのですか? newがGETリクエストでアクセスされているため、RESTfulルーティングに違反していませんか?でレコードを変更しないでください。

おそらく私は何か間違っています。私はレコードを別に作るべきですか?多分Subscription.new(user_id: user.id)経由ですか?あまり意味がないようです。

これがなぜこのように実装されているのか、これをどのように処理するのかについての説明がありがたいですか。

ありがとうございます!

答えて

2

それはあなたが投稿した何より


思考

を何をしたいのかに依存し、RESTful構造はまだあなたのために有効であると思われます。あなたはsubscriptionsコントローラでnewアクションを呼び出しています。これは定義上、新しいサブスクリプションを作成していることを意味します(現在のサブスクリプションをロードしていないことを意味します)。

Railsは、基本的にインスタンスメソッドを持つRubyクラスのグループであることを覚えておく必要があります。

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

@subscriptionを構築している:これは、私があなたの問題はあなたが要求/アクションを処理している方法だと思います

に合わない場合は、RESTful構造に完全に維持する必要がないことを意味します新しいActiveRecordオブジェクトですが、そのようにする必要はありません。

:あなたはおそらく、彼らがいない


ロジック

をすればおそらく、あなたはインスタンスメソッドでいくつかのロジックを含めることができます(彼らは1つを持っている場合)、サブスクリプションを変更したい、または関連付けを作成します

#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が呼び出されます。 1つの質問:user.build_subscriptionを呼び出した後、古いサブスクリプションはデータベースに残っていますか?

user.build_subscriptionを呼び出した後に出力user.persisted?user.subscription.persisted?とは何ですか?

サブスクリプションが存在するかどうかを確認する方法は、IMHOは絶対に有効であり、有効です。

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を表示するように得ることができる前に、私は最終的に、私のfields_forでそう:subscription

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

をサブスクリプションの正しい特異バージョンを持っていることができました私がサブスクリプションを複数作ったとすると、そしてそれは救いません。 しかし、今はすべてが機能します。

関連する問題