Rails, Polymorphic Association - rendering associated instances only

只谈情不闲聊 提交于 2019-12-25 04:13:50

问题


I'm trying to learn how to use polymorphic associations in my Rails 5 app.

I have models called Organisation, Proposal and Package::Bip.

The associations are:

Organisation

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

Proposal

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

Package::Bip

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

Package::Bip can be associated with either of Organisation or Proposal. I'm struggling to figure out how to show the Package::Bips that only belong to proposal in my proposal show and the same for organisation.

My package::bip table has these 2 columns:

#  ipable_id      :integer
#  ipable_type    :string

The type gets set to either Proposal or Organisation.

In my proposal show, I have:

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

I think the (@proposal) should be the constraining factor in deciding which package_bip instances to return. But, it isn't. I'm not sure what it's doing because all package_bips get rendered (including those that are associated with an organisation).

In my proposal controller, I have:

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

I added the above where scope to try and force the show to use only those that have Proposal set in the ipable_type attribute - but that doesnt do any thing to help.

I'm not sure if I'm supposed to make an if statement in the Package::Bips controller to see whether the ipable_type is proposal. I don't understand how to exctract associated instances of the polymorphic object so that I can just show the relevant ones in an index on the proposal show page (with the index being populated only with the instances that belong to the proposal).

I tried writing the index action of the Package::Bips controller as:

def index


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

    # authorize @bips
  end

That doesnt do anything at all. So I'm not sure why it at least doesnt give an error message.

Rendering the right view

In my proposals/show - I have:

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

That link goes to my views/package/bips/index.html. That view has:

  <% @bips.each do |ip| %>. 

That is currently listing out all of the bips (for both organisation and proposal). I thought that the @proposal in the link in proposal/show might constrain things, or the index action method in my bips controller might(above) might help. But neither of these things filter the instances.

If I write:

 <%= @proposal.bips.first.title %> 

in my proposals show view, it works to render the title.

Now my challenge is how to let the bip index view render the correct set of instances (only proposal or only organisation) depending on which page sent the request to render that view. Maybe I could write request referer to see if its an organisation controller or proposals controller request?

TRYING TO RENDER THE VIEW

views/proposals/show.html.erb

<% if @proposal.bips.present? %>
    <%= link_to package_bips_path(@proposal) do %> 
      <h6 style="margin:2%; "> Intellectual Property </h6>
    <% end %>
<% end %>

views/bips/index.html.erb

<% @bips.each do |ip| %>
   <%= ip.title.titleize %>
   <%= ip.classification.humanize %>
<% end %>

views/bips/show.html.erb

<%= @bip.title.titleize %></h5><p><%= @bip.status %>

proposals controller

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

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

bips controller

def index
    # if params[:status]
    #   @bips = Package::Bip.where(:status => params[:status])
    # else
    #   @bips = Package::Bip.all
    # end  

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

    # authorize @bips
  end

New attempt

I found this:

http://rails-bestpractices.com/posts/2010/09/23/generate-polymorphic-url/

I don't understand whether 'parent' where used in the article is some kind of keyword, or if i need to define it somewhere.

Im trying to nest my routes, so now:

resources :proposals do 
    namespace :package do
      resources :materials
      resources :insights
      resources :facilities
      resources :participants
      resources :fundings
      resources :facts
      resources :bips 
    end

... and the same for organisations.

But, I am getting errors. I think maybe the article has jumped forward a few steps. Are there conventions for using polymorphic paths?

I've now found this resource:

http://www.codequizzes.com/rails/learn-rails/polymorphism

The create action looks unusual to me. Can anyone explain the create action concept used in this approach?

NEXT ATTEMPT

new index action in the Package::Bips controller:

def index

    if Package::Bip.ipable_type: 'Proposal'
      @bips = Package::Bip.where(ipable_type: 'Proposal')
    elsif Package::Bip.ipable_type: 'Organisation'
      @bips = Package::Bip.where(ipable_type: 'Organisation')
    else
       @bips = Package::Bip.all
    end

But now, that still isn't letting me try to see if it works.

When I try to render a show view for a proposal, I get an error that says:

undefined method `package_bips_path' for #<#<Class:0x007fa72ea9b730>:0x007fa72ea93ee0>

This is the link that the show page contains:

<% if @proposal.bips.present? %>
    <%= link_to package_bips_path(@proposal) do %> 
    <h6 style="margin:2%; "> Intellectual Property </h6>
<% end %>

ANOTHER GO AT IT

bips controller, index action:

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

proposals show:

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

views/bips/index

<div class="container-fluid" style="margin-bottom: 50px">
  <h2 style="text-align: center">Intellectual Property Assets</h2>

    <div class="row">
      <div class="col-sm-10 col-sm-offset-1">
        <div class="row" style="margin-top:50px; margin-bottom:50px">
          <div class="col-md-8 col-md-offset-2">
              <span style="margin-right:50px; padding-left:50px"> 
                <%= link_to "All", action: :index %> 
              </span>  
              <span style="color:grey">·</span>
                <span style="margin-right:50px; padding-left:50px"> 
                  <%#= link_to "Intellectual Property we can offer", package_bips_path(:status => "Offered") %> 
                </span>
                <span style="color:grey">·</span>
                <span style="margin-right:50px; padding-left:50px">
                  <%#= link_to "Intellectual Property sought", package_bips_path(:status => "Sought") %>
                </span>
          </div>
        </div>
      </div>
    </div> 


    <div class="row">
      <div class="col-xs-10 col-xs-offset-1">
        <div class="table-responsive" style="margin-left:30px; margin-top:15px">
          <table class="table table-bordered">
            <tr>
              <td> <h5>Title</h5> </td>
              <td> <h5>Asset</h5> </td>
              <td> <h5>Added</h5> </td>

             <%# if policy(@package_ips).update? %> 
                <td> <h5>Manage this asset</h5></td> 
             <%# end %>

            </tr>
            <% @bips.each do |ip| %>


            <tr>

              <td>
                  <%= ip.title.titleize %>
              </td>
              <td>
                  <%= ip.classification.humanize %>
              </td>
              <td>
                  <%= ip.created_at.try(:strftime, '%e %B %Y') %>
              </td>

              <%# if policy(@package_ips).update? %>
                <td>  
                   <%#= link_to 'More details', package_bip_path(ip) %> <span style="color:grey">·</span>
                   <%#= link_to "Edit", edit_package_ip_organistion_path(@organisation) %>
                   <!-- <span style="color:grey">·</span> -->
                   <%#= link_to 'Destroy', ip, method: :delete, data: { confirm: 'Are you sure?' } %>
                </td>  
              <%# end %>   

            </tr> 
            <% end %> 
          </table>
        </div>
      </div>
    </div>          
</div>

This doesnt work (still renders wrong bips), BUT besides being incorrect, I can't have any links on the show page. If i want to link to :status params on the bips show view, it starts from a path that is not prefixed by proposal/organisation - so it doesnt work.

NEXT ATTEMPT

The bips controller index action now has:

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

This now renders bips, but it renders proposal bips in the organisation index (as well as the proposal index).

I'm stuck!

In the console, I can do:

p = Proposal.last
  Proposal Load (6.1ms)  SELECT  "proposals".* FROM "proposals" ORDER BY "proposals"."id" DESC LIMIT $1  [["LIMIT", 1]]
 => #<Proposal id: 15, user_id: 4, title: "testing filter",  created_at: "2016-11-08 00:59:09", updated_at: "2016-11-08 00:59:09"> 
2.3.1p112 :123 > p.bips
  Package::Bip Load (0.5ms)  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",  ipable_id: 15, ipable_type: "Proposal", created_at: "2016-11-08 00:59:09", updated_at: "2016-11-08 00:59:09"]> 

This is correct. I can also do:

o = Organisation.first
  Organisation Load (1.1ms)  SELECT  "organisations".* FROM "organisations" ORDER BY "organisations"."id" ASC LIMIT $1  [["LIMIT", 1]]
 => #<Organisation id: 1, title: "bhjhghdddd",  created_at: "2016-10-21 05:20:39", updated_at: "2016-11-06 21:36:30"> 
2.3.1p112 :125 > o.bips
  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", 1], ["ipable_type", "Organisation"]]
 => #<ActiveRecord::Associations::CollectionProxy []> 

This is also correct.

I just can't find a way to get the index populated with the right bips in the code.

ANOTHER ATTEMPT

I'm trying to use the advice in this tutorial: http://www.codequizzes.com/rails/learn-rails/polymorphism

It suggests:

# views/articles/show.html.erb
<%= render @article.comments %>

# views/comments/_comment.html.erb
<%= comment.body %><br />
The render @article.comments in the show page automatically knows to load a file called views/comments/_comment.html.erb. This is Rails magic, so just memorize this.

Taking that, I made a partial in my views/package/bips folder called _bips.html.erb.

In my proposals show view, I tried:

<%= render @proposal.bips %>

I get an error that says:

Missing partial package/bips/_bip with {:locale=>[:en], :formats=>[:html], :variants=>[], :handlers=>[:raw, :erb, :html, :builder, :ruby, :coffee, :jbuilder]}. Searched in:
  * "/Users/d/cv/cflive/app/views"

That is the right location. I'm wondering if this problem might have something to do with the routes being nested. My routes file now has:

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

Can anyone see why this approach isn't working?

来源:https://stackoverflow.com/questions/40455139/rails-polymorphic-association-rendering-associated-instances-only

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!