Rails 5 – 从父控制器上的编辑路径中排除特定实例
我在我的Rails 5应用程序中有用户,提案和潜力的模型。
用户创建提案,然后他们自己和其他人可以创建评论。
模型之间的关联是:
用户
has_many :proposals, dependent: :destroy has_many :potentials
提案
belongs_to :user has_many :potentials, inverse_of: :proposal accepts_nested_attributes_for :potentials, reject_if: :all_blank, allow_destroy: true
潜在
belongs_to :proposal, inverse_of: :potentials belongs_to :user
在我的路线文件中,我有两个潜在的资源。 我不确定我是否已经离开了滑雪道 – 我无法找到一个如何做到这一点的例子。 我有两个:
resources :potentials
以及:
resources :proposals do resources :potentials
我这样做的原因是,当用户创建提案时,他们可以使用嵌套字段表单来添加潜在属性。 当另一个用户看到该提案时,他们会获得一个新表单来添加:潜在的属性集(他们不会通过提案表单执行此操作)。
在我的潜力视图文件夹中,我有新的渲染forms的视图以及我的提案表单中包含的potential_fields_for(只有提案创建者可以使用嵌套字段)。
新/渲染表单有:
f
提案表格包括:
在我的提案控制器中,我正试图找到一种方法来排除第三方创建:来自提案表单中显示的字段的潜力。
def edit @proposal.potentials_build unless @proposal.potentials || @proposal.potential.user_id != current_user.id
我不希望投标创建者能够从投标表单中编辑这些字段,但即使我不触及它们,当我更新投标表单时,第三方潜在客户ID也会更新为投标创建者ID (不更新那些特定的第三方潜在属性)。
我试图改变提案控制器中的编辑操作,排除用户创建的非当前用户ID的潜力。 只有提案创建者可以编辑提案,因此我希望这将排除具有除proposal.user_id之外的用户ID的proposal.potential实例。
那不起作用。
有没有办法可以将提案#edit action限制为只有那些不是由提案创建者创建的潜在实例?
TARYN的建议
我试图采纳Taryn对此的看法。
在我的proposal.rb中,我做了2个范围:
scope :owner_potentials, ->{ where(user_id: potential.user_id ) } scope :third_party_potentials, ->{ where(user_id: != potential.user_id) }
我不相信这是编写范围的正确方法。 虽然我无法找到如何编写它们的参考,但在以前我试图学习如何编写它们的时候,我已收到建议以这种格式设置它们:
scope :owner_potentials, ->(user){ where(user_id: potential.user_id ) } scope :third_party_potentials, ->(user){ where(user_id: != potential.user_id) }
我也尝试过这种方式,但如果我不包含“(用户)”,我会得到与我相同的错误。 我不明白包含是做什么或应该做什么。
在我的提案控制器中,编辑操作,然后我尝试了以下各项:
# @proposal.potentials_build unless @proposal.potentials || @proposal.potential.user_id != current_user.id # @proposal.owner_potentials.build unless @proposal.owner_potentials #@potentials = @proposal.owner_potentials || @proposal.owner_potentials.build
第一个是我最初的尝试。 它没有用,促使我写这篇文章。
第二个是我认为应该写的方式。
第三个是直接结合Taryn的想法,看看是否应该如何编写(尽管我认为这更像是描述要做什么的一般方式)。
这些都不起作用。 对于此尝试的第二个版本,我收到一条错误消息:
NoMethodError at /proposals/17/edit undefined method `owner_potentials' for #
我认为这不起作用的原因是范围作为表在类上运行,而不是要编辑的特定实例。 我认为这篇文章解释了这一点。
提案有很多潜力,因此我们的想法是检查属于特定提案的所有潜力,以查看这些潜力中的任何一个是否具有与提案实例上的用户ID相同的用户ID。 我怎样才能做到这一点?
我不能写:
Proposal.owner_potentials.build unless Proposal.owner_potentials
在提案控制器编辑操作中,因为set_proposal方法正在选择要应用的编辑的正确提议。
我是否可以在控制器编辑操作中使用范围,其中范围正在测试has_many关系?
下一步尝试
我的下一个想法是尝试在Potential模型中定义范围,以便范围可以在类上运行。
我试过了:
scope :owner_potentials, ->{ where('user_id == potential.proposal.user_id' ) } scope :third_party_potentials, ->{ where('user_id != potential.proposal.user_id') }
我在codementor上花了好几个小时试图学习范围,我从上面开始学习的内容是我上面使用的语法是不正确的 – 但是我被certificate写的方式(位于post的顶部,给出了未定义变量的错误) )。 我不知道如何学习如何学习写作范围。
无论如何 – 接下来我尝试将我的Proposal控制器中的编辑操作更改为:
@proposal.potentials.owner_potentials.build unless @proposal.potentials.owner_potentials
现在,我保存并尝试时没有错误,但是当我尝试编辑提案时,我仍然可以编辑由第三方创建的潜力。 我不明白我是否没有有效地编写范围,或者这个解决方案是否因其他原因而无法工作。
我会考虑添加一个自定义范围的关联,例如owners_potentials
/ third_party_potentials
,将潜力限制为由所有者/所有者以外的人创建的。 然后,您可以在需要时使用这些范围。
例如
has_many :potentials, inverse_of: :proposal has_many :owner_potentials, ->{ where("potentials.user_id = proposals.creator_id") } has_many :third_party_potentials, ->{ where("potentials.user_id != proposals.creator_id") }
然后你可以这样做:
def edit @potentials = @proposal.owner_potentials || @proposal.owner_potentials.build
然后在表单中,具体使用您指定的那个:
<%= f.simple_fields_for @potentials do |f| %>
注意:代码尚未经过测试或经过健全检查,它可以让您了解您可以做的事情 – 让它实际工作留给读者练习;)