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| %> 

注意:代码尚未经过测试或经过健全检查,它可以让您了解您可以做的事情 – 让它实际工作留给读者练习;)