Rails has_one build_association在保存之前删除记录

时间:2014-01-06 08:27:12

标签: ruby-on-rails rest ruby-on-rails-4

所以之前已经提到过,但没有令人满意的答案。

考虑两个模型,UserSubscription相关联:

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 破坏性 ,这意味着只需 访问 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路由,因为使用GET请求访问new 不应该 修改记录?

或许我做错了什么。我应该以不同方式建立记录吗?也许通过Subscription.new(user_id: user.id)?似乎没有多大意义。

非常感谢您解释为什么以这种方式实施,以及您将如何处理此问题。

谢谢!

4 个答案:

答案 0 :(得分:3)

这取决于你想做什么


<强>思想

根据您发布的内容,RESTful结构似乎仍对您有效。您在new控制器上调用subscriptions操作,根据定义,这意味着您正在进行新订阅(不加载当前订阅)?

你必须记住,Rails基本上只是一组Ruby类,带有实例方法。这意味着如果不适合

,则无需完全保留RESTful结构

我认为您的问题是您处理请求/操作的方式:

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

@subscription正在构建一个新的ActiveRecord对象,但不一定是那样。您可能想要更改订阅(如果有订阅),或者如果他们没有

则创建关联

<强>逻辑

也许您可以在实例方法中包含一些逻辑:

#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 :(得分:1)

我也一直认为,如果之后调用user.build_foobaruser.save只会被写入数据库。一个问题:在调用user.build_subscription之后,旧订阅是否仍在数据库中?

调用user.persisted?后输出user.subscription.persisted?user.build_subscription是什么?

您检查订阅是否存在的方法是恕我直言,绝对正确且有效。

答案 2 :(得分:0)

我今天遇到了这个并且同意在调用build时从db中删除一些东西是一个非常意外的结果(导致我们有错误的数据)。正如您所建议的那样,只需简单地执行Subscription.new(user:user)即可轻松解决。我个人认为,与user.build_subscription相比,它的可读性要低得多。

答案 3 :(得分:0)

自2018年起,Richard Peck的解决方案为我工作:

 #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,如果我订阅了复数。然后它就不会存钱。 但现在,一切正常。