3

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.

B. Bulpett
  • 814
  • 12
  • 27
  • you didn't put the main `yield` – Mohammad AbuShady Apr 01 '15 at 03:54
  • @MohammadAbuShady in the html block above, I've put `<%= yield :admin_content %>`. I also tried just plain `<%= yield %>` but that didn't work either – B. Bulpett Apr 01 '15 at 03:57
  • What do the logs say? – vee Apr 01 '15 at 04:01
  • @vee `Started GET "/administrators/145a435c-6632-4d54-aca3-5e834b9e2d41/manage_accounts" for 127.0.0.1 at 2015-03-31 23:15:15 -0400 Processing by AdministratorsController#manage_accounts as HTML Parameters: {"id"=>"145a435c-6632-4d54-aca3-5e834b9e2d41"}` -- then it loaded the 15 user accounts -- then it says `Rendered administrators/_manage_accounts.html.erb (77.2ms)` – B. Bulpett Apr 01 '15 at 04:06
  • There weren't any errors – B. Bulpett Apr 01 '15 at 04:07
  • 1) Why are you using `{ :action => :manage_accounts }` instead of the path helpers? 2) What is the path to the partial at the top of this question? 3) Can you add the *full* log output to this question? – Ryan Bigg Apr 01 '15 at 06:16
  • @RyanBigg (1) Tried using path helper, which is manage_accounts_administrator for this partial, but it throws a "Missing Template" error. (2) Edited my question with logs from the request in question. Also posted my routes.rb file in case that helps. Thanks – B. Bulpett Apr 01 '15 at 12:27
  • The indentation in your routes is all over the place. Please correct. – Ryan Bigg Apr 01 '15 at 20:52
  • Sorry about indentation, didn't notice. Have corrected now. – B. Bulpett Apr 01 '15 at 22:30

1 Answers1

3

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.

Ryan Bigg
  • 106,965
  • 23
  • 235
  • 261
  • PERFECT! I cannot thank you enough. Did as you said and renamed the files (w/out underscore prefix). Then just removed the word "partial:" from the manage methods and presto! All is good. As for the other advice, I _would_ do it this way, but my users will also have access to methods in those controllers (account, etc..) and these "manage" methods are strictly for admins. So what I'm attempting to do is to keep the methods abstracted into this Administrators controller. The entire controller (and everything in it) is subject to authorization. Thanks again - you are Superman! – B. Bulpett Apr 01 '15 at 22:43
  • 1
    @B.Bulpett Rather than have an `Administrators` controller I would move these actions into an admin namespace. I have a guide for doing that here: https://github.com/radar/guides/blob/master/admin-namespace.md. I think if you keep the actions in one controller that the controller will gain too many responsibilities and become hard to manage. By splitting it out into multiple controllers you'll make this whole thing much easier to manage. – Ryan Bigg Apr 06 '15 at 21:42
  • Thanks! If I had it to do over again, I'd definitely take this approach. I'm a bit too far down the rabbit hole on this one. Thank you for this great advice! – B. Bulpett Apr 07 '15 at 23:26