ruby-on-railscontrollernestedbooleanbutton-to

Rails: Pass ID of nested resource from button_to to controller / to toggle boolean in admin view


I am sitting here since the Dawn of Times trying to toggle a boolean in Rails for an admin to validate submissions.

I have a standard "Article" model, which has_many "Prosols" (which in turn belongs_to "Article"). A Prosol has a boolean "profeat1". I am trying to toggle it thanks to a set of button_to (as follows). I am looping through the articles prosols, showing them in a bootstrap template, and showing for each a button to validate or not. The issue is that all buttons point to the first prosol. It seems that the prosol ID is not accurately passed to the controller.

No route matches {:action=>"unpro1", :article_id=>5, :controller=>"prosols", :id=>nil} missing required keys: [:id]

Here is the code.

article#show.html.erb - Adding lines from original Code

<% if admin_signed_in? %>

<% @article.prosols.in_groups_of(2) do |group| %>
 <div class="container-fluid">
  <% group.compact.each do |prosol| %>

  <div class="col-md-6">
  <div class="box3">
  <h4><%= prosol.title %></h4> <br>
  <%= prosol.body %> <br>

  <% if prosol.profeat1 == false %>
    <%= button_to "Do it", pro1_article_prosol_path(:article_id => @article.id, :id => @prosol.id), :class => 'btn btn-info'%>

  <% else %>
    <%= button_to "Undo it", unpro1_article_prosol_path(:article_id => @article.id, :id => @prosol.id), :class => 'btn btn-info'%>

  <% end %>
</div>
</div>
<% end %>
</div>
<% end %>
<% end %>

prosols_controller.rb

def pro1
  @article = Article.find(params[:article_id])
  @prosol = @article.prosols.find(params[:id])
  @prosol.update(profeat1: true)
  redirect_to article_path(@article)
end

def unpro1
  @article = Article.find(params[:article_id])
  @prosol = @article.prosols.find(params[:id])    
  @prosol.update(profeat1: false)
  redirect_to article_path(@article)
end

routes.rb

resources :articles do
  resources :prosols do
    post 'pro1', on: :member
    post 'unpro1', on: :member
  end
end

Right now I think the issue is with passing the nested resource (prosol) ID to controller. If you see a better/different way of achieving the end result, I will warmly welcome your advice. Again, my goal is to display all prosols for an article, with an admin button to validate or not. I have thoroughly tried everything else on StackO so far but to no avail.

Awaiting the Savior... Thanks in advance.

EDIT : THIS IS THE SOLUTION - article#show.html.erb

<% if prosol.profeat1 == false %>
  <%= button_to "Do it", pro1_article_prosol_path(:article_id => @article.id, :id => prosol.id), :class => 'btn btn-info'%>

<% else %>
  <%= button_to "Undo it", unpro1_article_prosol_path(:article_id => @article.id, :id => prosol.id), :class => 'btn btn-info'%>

<% end %>

My initial error had 2 sources: - pointing to the nested prosol with an @ instead of no pointer, as it was already pointed to in the loop - and bad leftovers in the Articles controller, as follows:

def show
 @article = Article.find(params[:id])
 @prosols = @article.prosols.all    <--- wrong
 @prosol = @article.prosols.build   <--- wrong
end

Great. Now it's beer o'clock.


Solution

  • The issue appears to be that you are using @prosol in your button, which has not been assigned and is therefore returning nil.

    Your loop defined in your comment, sets prosol, which is not @prosol. Drop the '@' symbol and you should be fine.

    -- edit--

    As in id => prosol.id ...

      <% if prosol.profeat1 == false %>
        <%= button_to "Do it", ..., :id => prosol.id), :class => 'btn btn-info'%>
    
      <% else %>
        <%= button_to "Undo it", ..., :id => prosol.id), :class => 'btn btn-info'%>
    
      <% end %>
    

    Your error is showing id => nil because @prosil is a nil object.