Search code examples
ruby-on-railsrenderyieldactionviewcontent-for

Rails 4 content_for and yield displays blank page


I'm trying to render the following partial:

<% content_for :admin_content do %>
  <h3>Listing All Accounts</h3>
    <%= paginate (@accounts) %>
    <table id="indexTable" class="table table-striped">
      ...
    </table>
    <%= paginate (@accounts) %>
  <br>

  <%= link_to 'New Account', new_account_path %>
<% end %>

(there are other similar partials as well)

... in the following layout:

<!DOCTYPE html>
<html>
<head>
...
</head>
<body>
    <%= render 'navigation' %>
    <% if notice %>
      <p class="alert alert-success"><%= notice %></p>
    <% end %>
    <% if alert %>
      <p class="alert alert-danger"><%= alert %></p>
    <% end %>
    <main>
        <%= render partial: 'admin_navigation' %>
        <%= yield :admin_content %>
    </main>
    <footer>
...
    </footer>
</body>
</html>

The reason I'm trying to use content_for is that I have a couple of other pages similar to the above partial that I want to render when a link is clicked in the navigation:

<div id="panel">
  <div class="navbar subnav navbar-inverse admin-nav" role="navigation">
    <div class="navbar-inner">
      <div class="container-fluid">
        <h2>Admin Dashboard</h2>
        <ul class="pager subnav-pager">
          <div class="btn-group btn-group-justified" role="group" aria-label="navigation">
            <span role=button><%= link_to "Manage Accounts", {:action=>"manage_accounts"}, :class => "btn btn-primary" %></span>
            <span role=button><%= link_to "Manage Customers", {:action=>"manage_customers"},  :class => "btn btn-primary" %></span>
            <span role=button><%= link_to "Manage Transactions", {:action=>"manage_acct_transactions"},  :class => "btn btn-primary" %></span>
          </div>
        </ul>
      </div>
    </div>
  </nav>
</div>

The above links call respective methods in the controller, which are as follows:

def manage_accounts
    @accounts = Account.order('id').page(params[:page]).per(15)
    render partial: 'manage_accounts'
  end

  def manage_customers
    @customers = Customer.order('lastname').page(params[:page]).per(15)
    render partial: 'manage_customers'
  end

  def manage_acct_transactions
    @acct_transactions = AcctTransaction.order('date DESC').page(params[:page]).per(15)
    render partial: 'manage_acct_transactions'
  end

But when you click the links in navigation, it just shows a blank page with no html at all. The console says that the objects are loaded as per the controller, and that the partial is being rendered. But where is it?

I've tried all kinds of ways to get this to work. The closest I got was actually without the content_for/yield and just calling the method, which of course rendered the partial as if it were its own page (bad). There used to be something called replace_html which would probably work for what I'm trying to do but I'm using Rails 4.1.8.

Initially, I set this navigation up with AJAX, but it just doesn't work here. These partials have links for CRUD actions as well as redirects. Using AJAX led to all kinds of CSRF errors and seems like it adds an unnecessary layer of complexity for something that should be pretty simple.

Why does the above code not render anything?

Am I taking the wrong approach?

Thanks

EDIT: adding logs for the page request..

Started GET "/administrators/145a435c-6632-4d54-aca3-5e834b9e2d41/adminview" for 127.0.0.1 at 2015-04-01 07:58:41 -0400
Processing by AdministratorsController#adminview as HTML
  Parameters: {"id"=>"145a435c-6632-4d54-aca3-5e834b9e2d41"}
  [1m[36mUser Load (0.6ms)[0m  [1mSELECT  `users`.* FROM `users`  WHERE `users`.`id` = x'145a435c66324d54aca35e834b9e2d41'  ORDER BY `users`.`id` ASC LIMIT 1[0m
  Rendered administrators/adminview.html.erb within layouts/admin (13.7ms)
  Rendered application/_navigation.html.erb (1.4ms)
  Rendered application/_admin_navigation.html.erb (1.8ms)
Completed 200 OK in 212ms (Views: 206.9ms | ActiveRecord: 0.6ms)


Started GET "/administrators/145a435c-6632-4d54-aca3-5e834b9e2d41/manage_accounts" for 127.0.0.1 at 2015-04-01 07:58:45 -0400
Processing by AdministratorsController#manage_accounts as HTML
  Parameters: {"id"=>"145a435c-6632-4d54-aca3-5e834b9e2d41"}
  [1m[35mUser Load (0.6ms)[0m  SELECT  `users`.* FROM `users`  WHERE `users`.`id` = x'145a435c66324d54aca35e834b9e2d41'  ORDER BY `users`.`id` ASC LIMIT 1
  [1m[36m (49.0ms)[0m  [1mSELECT COUNT(*) FROM `accounts`[0m
  [1m[35mAccount Load (11.8ms)[0m  SELECT  `accounts`.* FROM `accounts`   ORDER BY id LIMIT 15 OFFSET 0
  [1m[36mCustomer Load (12.7ms)[0m  [1mSELECT  `customers`.* FROM `customers`  WHERE `customers`.`id` = 490181591 LIMIT 1[0m
  [1m[35mCustomer Load (0.7ms)[0m  SELECT  `customers`.* FROM `customers`  WHERE `customers`.`id` = 189365990 LIMIT 1
  [1m[36mCustomer Load (0.5ms)[0m  [1mSELECT  `customers`.* FROM `customers`  WHERE `customers`.`id` = 24420774 LIMIT 1[0m
  [1m[35mCustomer Load (0.5ms)[0m  SELECT  `customers`.* FROM `customers`  WHERE `customers`.`id` = 772684056 LIMIT 1
  [1m[36mCustomer Load (0.5ms)[0m  [1mSELECT  `customers`.* FROM `customers`  WHERE `customers`.`id` = 862455622 LIMIT 1[0m
  [1m[35mCustomer Load (0.4ms)[0m  SELECT  `customers`.* FROM `customers`  WHERE `customers`.`id` = 417734356 LIMIT 1
  [1m[36mCustomer Load (0.4ms)[0m  [1mSELECT  `customers`.* FROM `customers`  WHERE `customers`.`id` = 220490343 LIMIT 1[0m
  [1m[35mCustomer Load (0.4ms)[0m  SELECT  `customers`.* FROM `customers`  WHERE `customers`.`id` = 685817728 LIMIT 1
  [1m[36mCustomer Load (0.4ms)[0m  [1mSELECT  `customers`.* FROM `customers`  WHERE `customers`.`id` = 53991993 LIMIT 1[0m
  [1m[35mCustomer Load (0.4ms)[0m  SELECT  `customers`.* FROM `customers`  WHERE `customers`.`id` = 676540929 LIMIT 1
  [1m[36mCustomer Load (0.4ms)[0m  [1mSELECT  `customers`.* FROM `customers`  WHERE `customers`.`id` = 726000565 LIMIT 1[0m
  [1m[35mCustomer Load (0.4ms)[0m  SELECT  `customers`.* FROM `customers`  WHERE `customers`.`id` = 554199658 LIMIT 1
  [1m[36mCustomer Load (0.6ms)[0m  [1mSELECT  `customers`.* FROM `customers`  WHERE `customers`.`id` = 767280416 LIMIT 1[0m
  [1m[35mCustomer Load (0.6ms)[0m  SELECT  `customers`.* FROM `customers`  WHERE `customers`.`id` = 237301229 LIMIT 1
  [1m[36mCustomer Load (0.6ms)[0m  [1mSELECT  `customers`.* FROM `customers`  WHERE `customers`.`id` = 209732030 LIMIT 1[0m
  Rendered administrators/_manage_accounts.html.erb (194.7ms)
Completed 200 OK in 217ms (Views: 132.9ms | ActiveRecord: 80.8ms)

Also, here is the routes.rb if that helps solve this problem..

Rails.application.routes.draw do
  devise_for :users, :controllers => { :registrations => "registrations" }
  devise_scope :user do
    post "/accounts/adminview" => "devise/sessions#new"
  end

  root 'home#index'
  get 'home/about'
  get 'home/help'
  get 'accounts/add_account', to: 'accounts#new'
  post 'accounts/add_account', to: 'accounts#create'

  resources :administrators do
    member do
      get :adminview
      get :manage_accounts
      get :manage_customers
      get :manage_acct_transactions
    end
  end

  resources :users do
    resource :customers
    resource :accounts
    resource :addresses
  end

  resources :accounts do
    resource :acct_transactions
  end

  resources :account_types, :accounts, :addresses, :administrators, :customers, :transaction_types, :acct_transactions, :users

end

Again, according to logs, it supposedly is loading the partial _manage_accounts, but I'm only seeing a blank page. I've tried using path helper but it throws a "Missing Template" error. Have tried lots of other things, instead of the action method but I still get the same result.


Solution

  • Why are you rendering partials as the views for your actions?

    def manage_accounts
      @accounts = Account.order('id').page(params[:page]).per(15)
      render partial: 'manage_accounts'
    end
    

    Calling render partial like this will only render the content of the partial and will not load the layout. If you want the layout (and it certainly sounds like you do) then rename this file to a normal view app/views/administrators/manage_accounts.html.erb and then remove the render call from your action altogether.

    I would also advise splitting each of these manage routes out into their own controllers, so instead you would have app/views/admin/accounts/index.html.erb, which would become the new view to manage accounts. I suggest this because it falls in line with the more traditional CRUD design of a Rails application.