Rails 5 - 从父控制器的编辑路径中排除特定实例

Rails 5 - exclude specific instances from edit path on parent controller

我的 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

我这样做的原因是当用户创建提案时,他们可以使用嵌套字段表单来添加潜在属性。当另一个用户看到该提案时,他们会得到一个新表单来添加一组 :potential 属性(他们不会通过提案表单来完成)。

在我的 potentials 视图文件夹中,我有新的视图,它呈现表单以及 potential_fields_for,它包含在我的提案表单中(只有提案创建者可以使用嵌套字段)。

new/render 表格有:

<%= simple_form_for [ @proposal, @potential ] do |f| %>
f

提案表格有:

<%= f.simple_fields_for :potentials do |f| %>
        <%= f.error_notification %>
          <%= render 'potentials/potential_fields', f: f %>

      <% end %>


      <%= link_to_add_association 'Add another novel aspect', f, :potentials, partial: 'potentials/potential_fields' %>
      </div>

在我的提案控制器中,我试图找到一种方法来从提案表单中显示的字段中排除第 3 方创建的 :potentials。

def edit
    @proposal.potentials_build unless @proposal.potentials || @proposal.potential.user_id != current_user.id

我不希望提案创建者能够从提案表单中编辑这些字段,但即使我不触及它们,第 3 方潜力上的用户 ID 也会更新为提案创建者 ID我更新了提案表格(没有更新那些特定的第 3 方潜在属性)。

我试图将提案控制器中的编辑操作更改为排除非当前用户 ID 的用户创建的潜力。只有提案创建者可以编辑提案,所以我希望这将排除 proposal.potential 的实例,这些实例的用户 ID 不是 proposal.user_id.

那不行。

有没有一种方法可以将 proposal#edit 操作限制为仅那些不是由提案创建者创建的潜在实例?

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) }

我也试过这种方法,但是如果我不包含“(user)”,我会得到同样的错误。我不明白那个包含做什么或应该做什么。

在我的提案控制器中,编辑操作,然后我尝试了以下各项:

# @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

第一个是我最初的尝试。它没有用,促使我写这个 post。

第二个是我认为应该写的方式。

第三个是直接结合 Taryn 的想法,看看是否应该这样写(尽管我认为这是描述要做什么的更一般的方式)。

None 这些作品。对于此尝试的第二个版本,我收到一条错误消息:

NoMethodError at /proposals/17/edit
undefined method `owner_potentials' for #<Proposal:0x007f84f6ca1700>

我认为这不起作用的原因是 class 上的范围是 运行 作为 table,而不是要编辑的特定实例。我认为 this post 解释了这一点。

提案有很多潜在客户,因此我们的想法是检查属于特定提案的所有潜在客户,以查看这些潜在客户中是否有任何潜在客户的用户 ID 与提案实例上的用户 ID 相同。我该怎么做?

我不会写:

Proposal.owner_potentials.build unless Proposal.owner_potentials

在提案控制器编辑操作中,因为 set_proposal 方法正在挑选正确的提案进行编辑。

我可以在控制器编辑操作中使用范围吗?has_many 关系正在被范围测试?

下一次尝试

我的下一个想法是尝试在 Potential 模型中定义范围,以便范围可以 运行 在 class 上。

我试过了:

scope :owner_potentials, ->{ where('user_id == potential.proposal.user_id' ) }
  scope :third_party_potentials, ->{ where('user_id != potential.proposal.user_id') }

我在 codementor 上花了几个小时试图学习作用域,我从那次会话中得到的收获是我上面使用的语法不正确 - 但我被证明是写它们的方式(在 post, 给出未定义变量的错误)。我不知道如何弄清楚如何学习编写范围。

无论如何-接下来我尝试将我的提案控制器中的编辑操作更改为:

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

注意:代码尚未经过测试或 sanity-checked,它在这里是为了让您了解您可以做什么 - 让它实际工作留作 [=26= 的练习] ;)