所以之前已经提到过,但没有令人满意的答案。
考虑两个模型,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
破坏性 ,这意味着只需 访问 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)
?似乎没有多大意义。
非常感谢您解释为什么以这种方式实施,以及您将如何处理此问题。
谢谢!
答案 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_foobar
,user.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,如果我订阅了复数。然后它就不会存钱。 但现在,一切正常。