1

Newbie to Rails, been playing, and trying to understand something about the convention & MVC approach. Coming from original object background, there is something bothering me with the rails paradigm and I can't find a good suggestion on the rationale / best approach.

Partials are only for rendering views? It does not 'call the controller'.

Let me illustrate: Say a home page that has 3 objects, 3 controllers and 3 sets of views

  • User
  • Address
  • User History

If I want a logged in home page which actually displays content from all models I seem to have to create say a 'site controller' and view, that is the home, page, but I have to replicate 'logic' in the site controller to setup variables for say user, address and user history that are then accessed via the various partials/forms.

In testing I have setup 3 sets of tests to get all the views and data working. But in the combined home page I seem to have to replicate controller logic into "site" central/home page.

In an "object world" my brains says I would have the ability to embed controller calls to support views so I can simply reuse address, user and user history controllers. * Or am I completely missing something as to how this works. Welcome views of experts or direction on what I'm mis-understanding.*

These examples seem too re-enforce my point and dong seem to deliver the solution

  1. reuse the view only
  2. to reuse a controller use a super class

Cheers Ben

Community
  • 1
  • 1
Ben
  • 1,292
  • 1
  • 13
  • 21

1 Answers1

1

No, partials don't call the controller. You instantiate the objects you need in the controller. So if you want to render an address partial you'd get the address in the controller.

If you need all 3 on all pages you could create controller concerns which have a before action on them

module GetStuff
  extend ActiveSupport::Concern

  included do
    before_action :set_user
    before_action :set_address
  end

  def set_user
     @user = # code for getting user
  end
end

class UsersController
  include GetStuff
end

Or assuming you inherit from application controller you could simply set a before action for them there (but if you have other controllers inheriting from it that's probably not the best idea.

If you use them frequently you could put methods in application controller and set helper methods to allow the methods to be accessible from views as well as controllers.

class ApplicationController
  def current_user
    @current_user = #code to get user
  end
  helper_method :current_user
end

# Some view
<% if current_user %>
  <%= current_user.username %>
<% end %>

Or you could have methods in helpers

module ApplicationHelper
  def current_user
    @current_user = #code to get user
  end
end

Or presumably address is linked to user too you could create a facade and simply instantiate that in your controllers

class UserController
  def show
    @user_facade = UserFacade.new(User.find(params[:id])
  end
end

class UserFacade
  attr_reader :user

  def initialize(user)
    @user = user
  end

  def address
    @address ||= user.address
  end

  def user_history
    @user_history ||= user.history
  end
end

# users/show.html.erb

<%= render @user_facade.user %>
<%= render @user_facade.address %>
<%= render @user_facade.user_history %>
j-dexx
  • 10,286
  • 3
  • 23
  • 36
  • thanks j-dexx - (apologies for not getting back, this 'fun' is part-time gig for me). This was useful and I've played with the different options and do like the UserFacade approach. – Ben Jun 23 '16 at 08:16
  • No worries. In addition you could delegate methods in the facade so you can do `@user_facade.name` rather than `@user_facade.user.name` – j-dexx Jun 23 '16 at 09:48