Rails 5 - 在编辑操作中使用范围来查找特定实例的相关子项 [英] Rails 5 - using a scope in an edit action to find relevant children of a specific instance

查看:39
本文介绍了Rails 5 - 在编辑操作中使用范围来查找特定实例的相关子项的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试学习如何在我的 Rails 5 应用中使用作用域.

我在这里问了一个背景问题.

在我的 Rails 5 应用中为用户、提案和潜在客户提供模型.

用户创建提案,然后他们自己和其他人可以对其发表评论.

模型之间的关联是:

用户

 has_many :proposals,dependent: :destroyhas_many :潜力

提案

belongs_to :userhas_many :potentials, inverse_of: :proposalaccepts_nested_attributes_for :potentials, reject_if: :all_blank, allow_destroy: true

潜力

belongs_to :proposal, inverse_of: :potentials归属地:用户

在我的路由文件中,我有两个潜在的资源.我不确定我是否已经离开了滑雪道——否则我找不到如何做到这一点的例子.我两个都有:

资源:潜力

以及:

resources :proposals do资源:潜力

目标:

当提出建议的用户尝试编辑它时,我只希望该用户能够编辑他们自己创建的潜力.

我为潜力设置了两条路线的原因是嵌套资源在提案表单内有一个嵌套的表单字段,因此提案创建者可以通过这种方式制作潜力.任何其他看到提案并产生潜力的用户都通过单独的表单进行操作.

任何用户(包括提案创建者,都可以通过单独的表单编辑潜力),提案创建者也可以通过提案表单中的嵌套表单编辑自己的任何提案.

目前,每当我编辑提案表单时(即使我不编辑潜在的嵌套字段),所有潜在客户都会更新以插入提案创建者的用户 ID,覆盖实际的潜在创建者的用户 ID.

解决方案

我试图限制提案控制器中的编辑操作,以便它只允许编辑具有 user_id ==提案.user_id 的提案/潜力.

为此,我在我的proposal.rb中写了范围

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

我上面喜欢的帖子中的解决方案是尝试使用范围.由于范围旨在用于类而不是实例,因此我一直试图弄清楚如何调整它们,以便我可以使用范围来搜索所有符合要求的潜力(即潜在的潜力.user_id == proposal.user_id).这意味着我不是在搜索 Proposal 类,而是在搜索特定的提案.

这篇文章建议在相关的控制器动作中定义 Event.all ,但是如何我限制了它,所以它只适用于特定的电位编辑行?我的编辑操作中有其他行不应在 Proposal 表上进行测试,而应仅在实例上进行测试.如果这能够奏效,我想我将需要重写我的范围以尝试排除所有其他提案.

有没有办法在具有范围的控制器中在特定实例上使用编辑操作?

解决方案

Scopes 定义查询用于定义它们的 AR 类.你说你已经写了 owner_potentials 和proposal.rb 中的 third_party_potentials 范围.但是,如果这些范围旨在返回一组电位,那么这些应该在 Potential 类中定义.如果您需要从提案记录访问这些范围,您可以将范围链接到关联,例如

类潜力范围:owner_potentials,->(用户){ where(用户:用户)}范围:third_party_potentials,->(用户){ where.not(用户:用户)}结尾...class ProposalsController # Proposals::PotentialsController..?imo Proposals::PotentialsController#edit 听起来像是只编辑一个潜在记录的端点,而没有其他任何内容,这听起来不像您想要的.您对如何构建控制器/路由的要求.定义编辑@proposal = ... # 无论你的逻辑是什么找到提案@proposal.potentials.owner_potentials(current_user) # 对用户的潜力做一些事情@proposal.potentials.third_party_potentials(current_user) # 用用户不拥有的潜力做一些事情结尾结尾

您可以在此处看到如何将关联 (.potentials) 链接到范围 (.owner_potentials).

此外,如果您有关联,则可以将该关联视为 where 方法中的一个字段,使用 where(user: user) 而不是 >where(user_id: user.id).

最后要注意的是,您可能希望通过此重构更改作用域的名称.potentials.owner_potentials(user) 有点多余.也许像 potentials.owned_by(user) ?

I am trying to learn how to use scopes in my Rails 5 app.

I have asked a background question here.

have models in my Rails 5 app for User, Proposal and Potential.

Users create Proposals which they themselves and others can then create comments on.

The associations between models are:

User

  has_many :proposals, dependent: :destroy
  has_many :potentials

Proposal

belongs_to :user
has_many :potentials, inverse_of: :proposal
    accepts_nested_attributes_for :potentials, reject_if: :all_blank, allow_destroy: true

Potential

belongs_to :proposal, inverse_of: :potentials
  belongs_to :user

In my routes file, I have two resources for potentials. I'm not sure if I've gone off piste with this bit- I cant find an example of how to do this otherwise. I have both:

resources :potentials

as well as:

resources :proposals do

    resources :potentials

Objective:

When the user who made the proposal tries to edit it, I only want that user to be able to edit the potentials that they created themselves.

The reason I have two routes set up for potentials is that the nested resource has a nested form fields inside the proposal form, so that the proposal creator can make a potential in that way. Any other user that sees the proposal and makes a potential does it via a separate form.

Any user (including the proposal creator, can edit the potential via that separate form), and the proposal creator can also edit any of its own proposals by the nested form in the proposal form.

At the moment, whenever I edit the proposal form (even when I don't edit the potential nested fields), all of the potentials are updated to insert the proposal creator's user id overriding the actual potential creator's user id.

Solution

I am trying to limit the edit action in the proposals controller, so that it only allows the proposal /potentials to be edited if they have the user_id == the proposal.user_id.

For this purpose, I have written scopes in my proposal.rb

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

The solution in the post i liked above was to try using a scope. Since scopes are meant to work on the class, rather than an instance, I'm stuck in trying to figure out how to adapt them so that I can use the scope to search for all the compliant potentials (i.e. potentials where potential.user_id == proposal.user_id). That means Im not searching the Proposal class, Im searching the specific proposal.

This post suggested defining Event.all inside the relevant controller action, but then how would I limit that so it only applied to the specific potentials edit line? I have other lines in my edit action which should not be tested on the Proposal table, but just the instance. If this were able to work, I imagine I would then need to rewrite my scope to try to exclude all the other proposals.

Is there a way to use an edit action in a controller with a scope, on a specific instance?

解决方案

Scopes define queries for the AR class they are defined in. You say you have written owner_potentials and third_party_potentials scopes in proposal.rb. But if these scopes are meant to return a collection of potentials, then these should be defined in the Potential class. If you need to access these scopes from a proposal record, you can chain scopes to associations, e.g.

class Potential
  scope :owner_potentials, -> (user) { where(user: user) }
  scope :third_party_potentials, -> (user) { where.not(user: user) }
end

...

class ProposalsController # Proposals::PotentialsController..? imo Proposals::PotentialsController#edit sounds like an endpoint for editing exactly one potential record and nothing else, which doesn't sound like what you want. Your call on how to structure the controller/routes though.
  def edit
    @proposal = ... # Whatever your logic is to find the proposal

    @proposal.potentials.owner_potentials(current_user) # do something with the user's potentials
    @proposal.potentials.third_party_potentials(current_user) # do something with the potentials the user doesn't own
  end
end

You can see here how you chain an association (.potentials) to a scope (.owner_potentials).

Also, if you have an association, you can treat that association as a field in a where method, a la where(user: user) instead of where(user_id: user.id).

Last thing to note is that you probably want to change the name of the scopes with this refactor. potentials.owner_potentials(user) is a bit redundant. Maybe something like potentials.owned_by(user) ?

这篇关于Rails 5 - 在编辑操作中使用范围来查找特定实例的相关子项的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆