Rails 5 - 使用多态关联 - 渲染视图

Posted

技术标签:

【中文标题】Rails 5 - 使用多态关联 - 渲染视图【英文标题】:Rails 5 - using polymorphic associations - rendering the views 【发布时间】:2016-11-10 01:58:45 【问题描述】:

我正在尝试学习如何在我的 Rails 5 应用程序中使用多态关联。我最近问了this的问题,但是我编辑了很多次以显示我正在尝试的所有东西,它变得凌乱了

我有称为组织、提案和包装的模型::Bip。

这些关联是:

组织

has_many :bips, as: :ipable, class_name: Package::Bip
    accepts_nested_attributes_for :bips,  reject_if: :all_blank, allow_destroy: true

建议

has_many :bips, as: :ipable, class_name: Package::Bip
    accepts_nested_attributes_for :bips,  reject_if: :all_blank, allow_destroy: true

包::Bip

belongs_to :ipable, :polymorphic => true, optional: true #, inverse_of: :bip

Package::Bip 可以与组织或提案相关联。我正在努力弄清楚如何在我的提案节目中显示仅属于提案的 Package::Bips,并且对于组织也是如此。

我的 package::bip 表有这两列:

#  ipable_id      :integer
#  ipable_type    :string

ipable_type 设置为提案或组织。

在我的求婚秀中,我有:

<% if @proposal.bips.present? %>
    <%#= render @proposal.bips %>
     <%= link_to proposal_package_bips_path(@proposal) do %> 
     <% end %>
<% end %>

我找到了this 的帖子。我理解这意味着我也应该能够尝试:我也尝试过:

<% if @proposal.bips.present? %>
    <%= render @proposal.bips %>
<% end %>

我认为 (@proposal) 应该是决定返回哪些 package_bip 实例的约束因素。但是,事实并非如此。我不确定它在做什么,因为所有 package_bips 都会被渲染(包括那些与组织相关的)。

在我的提案控制器中,我有:

 def index
    @proposals = Proposal.all
    # @bips = @proposal.bips
    # authorize @proposals
  end


def show
    @bips = @proposal.bips#.where(ipable_type: 'Proposal')
end

在我的 Package::BipsController 中,我有

def index

    if params[:ipable_type] == "Proposal"
      @bips = Package::Bip.where(:ipable_type == 'Proposal')
    else params[:ipable_type] ==  'Organisation'
      @bips = Package::Bip.where(:ipable_type == 'Organisation')
    end

但是,当我保存所有这些并尝试时,我得到了错误的结果。

目前,数据库中有 4 个 Package::Bip 实例。

Package::Bip.pluck(:ipable_type)
   (0.8ms)  SELECT "package_bips"."ipable_type" FROM "package_bips"
 => ["Proposal", "Proposal", "Proposal", "Organisation"] 

3 个属于提案,1 个属于组织。

属于提案的 3 个分别属于不同的提案。

Package::Bip.pluck(:ipable_id)
   (0.8ms)  SELECT "package_bips"."ipable_id" FROM "package_bips"
 => [15, 13, 16, 1] 

我的目标是提案展示视图或组织展示视图应该只显示属于该特定提案的 Bips。

但是,当我呈现我的提案展示视图时,它有:

<%= link_to proposal_package_bips_path(@proposal) do %> 

反过来,我的 views/package/bips/index.html.erb 有:

<% @bips.each do |ip| %>
   <%= ip.title.titleize %>
      <%#= link_to 'More details', package_bip_path(ip) %> 

我希望这个视图能够呈现一个包含 1 个 package_bip 实例的列表。相反,我列出了所有 4 个实例(proposal.bips 中的 2 个属于不同的提案,其中一个 bips 属于一个组织)。这些都不应该在索引中呈现。

此外,我无法将 bips/index.html.erb 中的链接添加到 bips/show.html.erb。这是因为该链接看起来像:

<%= link_to 'More details', package_bip_path(ip) %> <

当我尝试呈现包含该链接的索引时,我收到一条错误消息:

undefined method `package_bip_path' for #<#<Class:0x007fbce68389c0>:0x007fbcfdc31c18>

我认为链接可能需要包含提案或组织。

我的路线是嵌套的:

resources :proposals do 
    namespace :package do
      resources :bips 
    end

resources :organisations do 
  namespace :package do
    resources :bips 
  end

从控制台,我可以使用我想要应用的过滤器进行搜索。

p = Proposal.last
  Proposal Load (4.8ms)  SELECT  "proposals".* FROM "proposals" ORDER BY "proposals"."id" DESC LIMIT $1  [["LIMIT", 1]]
 => #<Proposal id: 16, user_id: 4, title: "test tenor", description: "test tenor",  created_at: "2016-11-08 21:58:38", updated_at: "2016-11-08 21:58:38"> 
2.3.1p112 :199 > p.bips
  Package::Bip Load (0.3ms)  SELECT "package_bips".* FROM "package_bips" WHERE "package_bips"."ipable_id" = $1 AND "package_bips"."ipable_type" = $2  [["ipable_id", 16], ["ipable_type", "Proposal"]]
 => #<ActiveRecord::Associations::CollectionProxy [#<Package::Bip id: 19, identifier: "test tenor", description: nil, conditions: "test tenor", ipable_id: 16, ipable_type: "Proposal", created_at: "2016-11-08 21:58:38", updated_at: "2016-11-08 21:58:38", title: "test tenor", status: nil, classification: "Copyright">]> 
2.3.1p112 :200 > p.bips.count
   (3.5ms)  SELECT COUNT(*) FROM "package_bips" WHERE "package_bips"."ipable_id" = $1 AND "package_bips"."ipable_type" = $2  [["ipable_id", 16], ["ipable_type", "Proposal"]]
 => 1 

但这在我的任何尝试中都不会延续到代码中。

任何人都可以向我推荐可以帮助我弄清楚如何设置我的多态视图的资源,以便它们能够正确过滤,以便我可以使用典型的索引链接(例如,显示/编辑),以便他们可以被认为属于提案/组织中的一个或另一个?

更新

我现在找到了this 帖子。

我尝试采用它建议的流程:

    将提案控制器中的创建操作更改为:

    定义创建 如果参数 [:organisation_id] 父 = Organisation.find(params[:organisation_id]) elsif 参数[:proposal_id] 父 = Proposal.find(params[:proposal_id]) 结束

    bip = Package::Bip.new
    Package::Bip.ipable = parent
    # @bip = Package::Bip.new(bip_params)
    # authorize @bip
    
    respond_to do |format|
      if @bip.save
        format.html  redirect_to @bip 
        format.json  render :show, status: :created, location: @bip 
      else
        format.html  render :new 
        format.json  render json: @bip.errors, status: :unprocessable_entity 
      end
    end
    

    结束

    将提案视图更改为:

当我尝试这个时,我没有收到任何错误,但所有 Package::Bips 都显示在提案显示视图中。

尽管存在具有组织 ID 的 Package::Bips。

Package::Bip.all.pluck(:ipable_type)
   (0.9ms)  SELECT "package_bips"."ipable_type" FROM "package_bips"
 => ["Proposal", "Proposal", "Proposal", "Organisation", "Proposal"] 

当我重新启动服务器并重试时,我收到一条错误消息:

undefined method `empty?' for #<Class:0x007ff20920e218>

错误信息指向我的新行:

<%= polymorphic_path(@proposal, Package::Bip) %>

日志显示:

Started POST "/__better_errors/3f34303f5f5c670f/variables" for ::1 at 2016-11-13 10:58:13 +1100
  Package::Bip Load (0.4ms)  SELECT "package_bips".* FROM "package_bips" WHERE "package_bips"."ipable_id" = $1 AND "package_bips"."ipable_type" = $2  [["ipable_id", 15], ["ipable_type", "Proposal"]]

这个post 显示了类似的问题,通过在路径中添加“[]”来解决。

然后我尝试:

<%= link_to polymorphic_path([@proposal, Package::Bip]) do  %>

我仍然得到所有 bip 的列表(即使是那些属于一个组织或具有不同 id 的提案的那些)。

我可以从日志中看到的内容可能是一个线索(如果是的话 - 它超出了我的想象)。

Started GET "/proposals/15/package/bips" for ::1 at 2016-11-13 11:24:32 +1100
Processing by Package::BipsController#index as HTML
  Parameters: "proposal_id"=>"15"
  User Load (1.1ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT $2  [["id", 4], ["LIMIT", 1]]
  Rendering package/bips/index.html.erb within layouts/application
  Package::Bip Load (0.6ms)  SELECT "package_bips".* FROM "package_bips"
  Rendered package/bips/index.html.erb within layouts/application (5.4ms)

日志似乎没有显示任何迹象表明它正在将提案或提案 ID 过滤器应用于 package_bips。

这对我来说没有任何意义,因为我的路线只能以组织或提案为前缀:

rake routes | grep package_bip
            organisation_package_bips GET      /organisations/:organisation_id/package/bips(.:format)                  package/bips#index
         new_organisation_package_bip GET      /organisations/:organisation_id/package/bips/new(.:format)              package/bips#new
        edit_organisation_package_bip GET      /organisations/:organisation_id/package/bips/:id/edit(.:format)         package/bips#edit
             organisation_package_bip GET      /organisations/:organisation_id/package/bips/:id(.:format)              package/bips#show
                proposal_package_bips GET      /proposals/:proposal_id/package/bips(.:format)                          package/bips#index
             new_proposal_package_bip GET      /proposals/:proposal_id/package/bips/new(.:format)                      package/bips#new
            edit_proposal_package_bip GET      /proposals/:proposal_id/package/bips/:id/edit(.:format)                 package/bips#edit
                 proposal_package_bip GET      /proposals/:proposal_id/package/bips/:id(.:format)                      package/bips#show

此外,当我尝试在最后一个链接的帖子中使用显示路径时,在我的 views/package/bips/index.html.erb 中为:

 <% @bips.each do |ip| %>
    <%= link_to polymorphic_path([@ipable, ip]) %>

然后我收到一条错误消息:

undefined method `package_bip_path' for #<#<Class:0x007f9e8ac29248>:0x007f9e939c9508>

TARYN 寻找问题的建议

背景。在我的提案控制器中,我的提案被定义为:

def set_proposal
   @proposal = Proposal.find(params[:id])
end

在控制台中,我尝试:

params = :proposal_id => 15
 => :proposal_id=>15 


2.3.1p112 :031 > @proposal = Proposal.find(params[:proposal_id])
  Proposal Load (0.7ms)  SELECT  "proposals".* FROM "proposals" WHERE "proposals"."id" = $1 LIMIT $2  [["id", 15], ["LIMIT", 1]]
 => #<Proposal id: 15, user_id: 4, title: "testing filter", description: "testing filter", byline: "testing filter", nda_required: true, created_at: "2016-11-08 00:59:09", updated_at: "2016-11-08 00:59:09"> 

2.3.1p112 :033 > @proposal.bips
  Package::Bip Load (0.7ms)  SELECT "package_bips".* FROM "package_bips" WHERE "package_bips"."ipable_id" = $1 AND "package_bips"."ipable_type" = $2  [["ipable_id", 15], ["ipable_type", "Proposal"]]
 => #<ActiveRecord::Associations::CollectionProxy [#<Package::Bip id: 17, identifier: "testing filter", description: nil, conditions: "testing filter", ipable_id: 15, ipable_type: "Proposal", created_at: "2016-11-08 00:59:09", updated_at: "2016-11-08 00:59:09", title: "testing filter", status: nil, classification: "Patent">, #<Package::Bip id: 21, identifier: "dd", description: nil, conditions: "dd", ipable_id: 15, ipable_type: "Proposal", created_at: "2016-11-10 22:47:54", updated_at: "2016-11-10 22:47:54", title: "ldsjflkjklsdjfl", status: nil, classification: "Design">]> 
2.3.1p112 :034 > @proposal.bips.count
   (6.3ms)  SELECT COUNT(*) FROM "package_bips" WHERE "package_bips"."ipable_id" = $1 AND "package_bips"."ipable_type" = $2  [["ipable_id", 15], ["ipable_type", "Proposal"]]
 => 2 

这给出了正确的结果。

在提案控制器中,显示操作,我有:

def show
    @images = @proposal.images
    byebug
    puts 'testing proposal controller'
    @bips = @proposal.bips#.where(ipable_type: 'Proposal')
  end

当我尝试这个时,我可以探索提案参数:

params
<ActionController::Parameters "controller"=>"proposals", "action"=>"show", "id"=>"15" permitted: false>
(byebug) proposal_params
*** ActionController::ParameterMissing Exception: param is missing or the value is empty: proposal

nil

其他有此问题的人将其归因于他们强大的 params 方法中的“require”语句。

我的 proposal_params 定义为:

def proposal_params
      params.require(:proposal).permit(:title, :description, :byline, :nda_required, :randd_maturities_list,
        #Package
        bips_attributes:            [:id, :status, :classification, :identifier, :conditions, :title, :_destroy,
          tenor_attributes:           [:id, :express_interest, :commencement, :expiry, :enduring, :repeat, :frequency, :_destroy]

        ],


       )
    end

我认为它是正确的。

不过,这些消息很奇怪,因为我还可以查看 bye bug 语句中的每个列入白名单的项目并获得正确的响应。例如:

 @proposal.id
15

当我尝试在 Package::bips 控制器中使用 bye bug 进行探索时,我可以看到:

params.inspect
"<ActionController::Parameters \"controller\"=>\"package/bips\", \"action\"=>\"index\", \"proposal_id\"=>\"15\" permitted: false>"

allowed: false 属性似乎是我的代码中的一个问题。

这是我的下一个问题。

【问题讨论】:

好的,所以您目前没有向我们展示您如何在控制器中设置 @proposal。 (它可能不相关,但我们会看到)。在您的控制台中,如果您真的完全按照您的控制器将执行的操作,那就太好了 - 例如,而不是 p = Proposal.last 执行 params = :proposal_id =&gt; 0 然后 @proposal = Proposal.find(params[:proposal_id])(或您的控制器中的任何内容)。那就试试@proposal.bips 我将在控制器中进行更多的登录,并尝试找到获取 bip 的来源。感谢您的提示。 我放弃了。我将为提案/组织 bips 制作 2 个单独的资源,然后继续。很难弄清楚这一点,如果我坚持努力学习,我不会迷失在另一个黑色整体中。非常感谢你也同样帮助我。 @TarynEast - 我简直不敢相信,但我找到了答案。就在这篇文章中 - 您可能可以更了解我可以使用的 load_commentable 方法。再次感谢您对此提供的所有帮助。rubyplus.com/articles/3901-Polymorphic-Association-in-Rails-5 我讨厌放弃一些事情。 :) 【参考方案1】:

答案在这里:https://rubyplus.com/articles/3901-Polymorphic-Association-in-Rails-5

诀窍似乎在文章中显示的 load_commentable 方法中。这对我来说太复杂了,无法理解,但它确实有效。

非常感谢乐于分享他们所知道的人们所提供的帮助。谢谢 Taryn 和 Bala。

【讨论】:

以上是关于Rails 5 - 使用多态关联 - 渲染视图的主要内容,如果未能解决你的问题,请参考以下文章

Rails 从视图中调用操作

为啥 Rails 渲染视图如此缓慢?

Rails -> 部分视图的操作方法

Rails 3 - 从视图中渲染 PDF 并附加到电子邮件

渲染布局和视图,rails

Rails递归查看对象关联的奇怪行为