Here is my problem with Rails.
Sometimes there is independent blocks at the page (e.g. "Latest news") which has no logical relation to current controller or action. In regular rails MVC stack I would write #news = News.latest in my controller and render 'shared/latest_news', news: #news in my view.
However its too much for me for several reasons. Instead I want to write render 'shared/latest_news', locals_call: "NewsController#latest" in view and that's it.
What should happen behind this row is calling "NewsController#latest" method to receive a hash of locals used in rendering this template.
Does anyone know gem for such calls?
You could make a universal helper method in ApplicationHelper:
def latest_news_tag
render partial: 'shared/latest_news', locals: { news: News.latest }
end
You can call this method in any view you want, e.g. <%= latest_news_tag %>.
Related
The Rails guide Layouts and Rendering in Rails gives examples of render being used in both the controller and the view.
The section Rendering by default ... mentions that rendering is called by default. The section Using render gives an example of render being called within a controller:
def update
#book = Book.find(params[:id])
if #book.update(book_params)
redirect_to(#book)
else
render "edit"
end
end
The section Using Partials gives an example of render being used within the view, for example to use partials.
<%= render "menu" %>
Neither the cases of render being used in controller, nor the case of render being used in the view, strike me as illogical. But what's confusing me is that I thought one of the major concepts of Rails is model view controller separation, which means giving separate responsibilities to the model, view, and controller.
Why is it normal for render to be called in both the controller and in the view?
I'd say that if used properly, when render is used in a view, it should be primarily as an organization/structural tool in order to make the code for the view more understandable and readable.
When used in a controller, it's defining the entry point into the view and is the primary association between the action in the controller and the view.
The difference is subtle.
I understand this is a bad idea, but from what I've seen in ApplicationControllers, using:
render :layout => "something" ...
Should render using a layout located at views/layouts/something.html.erb
However, when I am making this call from inside of a view, it errors out with:
Missing partial my_controller_name/something with ...
Searched in:
* "{path here}/app/views"
Which seems to me its looking for a partial, instead of a layout as I specified. Does anyone know what is going on with that?
A sufficient example small enough to reproduce it:
<%= render :layout => 'something' do %>
<div>Hello</div>
<% end %>
This is all under Rails vs 4.0.2
render works differently in controllers than it does in views. In controllers, it's primarily for rendering action templates, while in views, it's primarily for rendering partial templates. When you want to render a specific layout for an action, you have a few options, but all of them are in the controller.
If you want every action in a particular controller to use that layout, you can either specify layout 'something' in that controller (usually near the top) or for a ApplesController, you can create a new layout in app/views/layouts/apples.html.erb and this will automatically be used as the default layout for the ApplesController.
If you want just a single action in a controller to use that layout, you can use your render layout: 'something' inside of a controller action, where the action to render is implied to be the current action.
Links from the Rails docs:
Action Rendering
Partial Rendering
Nested Layouts
Somewhat new to rails, longtime programmer. I've got a question about views, controllers and partials really - wondering if I have this setup well.
I've got a pages controller, and on the index page (really the pages index method) I've got a partial in layouts called featured (ie app/views/layouts/_featured.html.erb) -- I've also got a Featured class. I would like basically the index of the featured class to be drawn here. But of course it's not working. SO the question is:
In the page itself I've got the <%= render 'features/index' %> which I'm beginning to think is the wrong way to go..
Do I axe this partial method and just call <%= render 'features/index' %> and let everything progress natively or
What would be the proper way of routing the featured collection to the partial? Since the controller is actually Pages it seems like I'm fighting against the tide.
<%= render 'features/index' %>
Doing this is wrong given your description. This will try to render a partial from app/views/features/_index.html.erb which you haven't mentioned.
To render the partial at app/views/layouts/_featured.html.erb you would do (perhaps a bit more verbose that is necessary)
<%= render partial: "layouts/featured" %>
The best suggestion I can offer is to pass a collection to this partial
<%= render partial: "layouts/featured", locals: { features: #features } %>
Since it seems your intention is for this partial to appear as a piece of a layout I will assume you wish for this partial to appear on multiple pages. This means on multiple actions you will need to have assigned the set of Feature instances this #features instance variable. One way to do this is a before_action.
before_action :setup_features
# ...
private
def setup_features
#features = Feature.all
end
A good place to start learning more about filters is in the Rails Guide
The partial at "app/view/layouts/_featured.html.erb" can only be rendered with
render 'featured'
and not 'featured/index'
render 'featured/index' will render "app/views/layouts/featured/_index.html.erb
Since the pages controller is really rendering the main index page in it's def index, all I had to do was #features = Feature.all and the variable is available for the partial pulled into the index page.
I need to get used to how simple rails is coming from other languages / frameworks.
I come from PHP and CakePHP background and I'm pretty new to ruby and rails.
I've been creating a helper that could help me with creating some HTML elements that could make me easy to reuse across the web app that I am creating.
Here's how the snippet of my helper looks like
module VehicleHelper
def mileage(vehicle)
render partial: "vehicles/shared/mileage", { locals: vehicle }
end
def manufacturer(vehicle)
render partial: "vehicles/shared/manufacturer", { locals: vehicle }
end
#and etc...
end
And I would use it this way in haml.
%h1= #vehicle.name
= mileage #vehicle
= manufacturer #vehicle
-# and etc…
I want to be able to scope it, so that I don't need to give #vehicle as an argument for every function. Like
%h1= #vehicle.name
- vehicle_block_for #vehicle do
= mileage
= manufacturer
-# and etc…
How do I achieve it? Is that a right pattern that I should use?
Edit : I have thought of using partials straight in the view. However, the problem is that I not only have Vehicle class, I also have Car and Bike classes which are sub-classes of Vehicle, following the STI pattern.
Which means I will have to pass locals all the time, in which case = render partial: 'mileage', { locals: vehicle} or what not becomes configuration codes. And let's say I've renamed the file or moved it somewhere, then I'd have to go and modify all these codes.
About whether this is a "right pattern" for you to use, that's entirely up to you. If you like the way it makes the code read, then great. The simplest implementation would be something like:
module VehicleHelper
def vehicle_block(vehicle)
old,#__vehicle__ = #__vehicle__,vehicle
yield
#__vehicle__ = old
end
def mileage
render partial: "vehicles/shared/mileage", { locals: #__vehicle__ }
end
end
You could just make the render calls directly in your view and it will automatically have access to your instance variable "#vehicle"... I believe those views would have access to "#vehicle" as we'll using the helper methods you currently have, no need to pass it as an argument.
I would also check out the presenter/decorator pattern for this. There is a Railscast for it.
Is that a right pattern that I should use?
I would say no. Yes, you're shortening the code but at the cost of making things harder to follow/understand. A new user to your project would have to search around for the definition of the "mileage" method. Once they find it in the helper they would have to go look at the partial. All that for what, showing less code in the view? I don't think it's worth it.
I would revert it back to something like the following which IMHO is much easier to follow and more idiomatic rails.
%h1= #vehicle.name
render partial: 'mileage', { locals: vehicle }
render partial: 'manufacturer', { locals: vehicle }
Note: I would also explicitly pass in the locals instead of using #vehicle. It makes things, well, more explicit.
In my rails application, I render a partial on multiple pages, and in that partial is a variable. So currently, lets say I have 5 pages that render :partial => "partialname", and inside of partialname is #variable.
Can I have it so that partialname has its own action with #variable instantiated inside, rather than having #variable be called 5 times from each action that renders the partial?
Thanks!
I would create a before_filter on all the methods that need the common behavior.
But if you really want the partial to have its own "action," make a helper method that does whatever "action-y" things you want and then renders the partial. That works out to essentially the same thing. I've done this before to make a template-type partial that contains various pieces of data that need processing.
Rails Sub-controllers?
See my answer on this.
Very similar method here, using before filters either using controller inheritance or modules when needed.
So, is this a problem of code running 5 times per request that you'd rather not? Like, you've got a partial and in it is:
#my_var = MyModel.some_expensive_method
If so, you could just cache the result in the model:
def cached_some_expensive_method
#some_expensive_method ||= some_expensive_method()
end
you could load #variable from the view:
<% #variable = Variable.find(:whatever) %>
but some consider this bad practice in not adhering to strict MVC. This does have the benefit of supporting fragment caching out of the box:
<% cache({:variable_id => :whatever}) do %>
<% #variable = Variable.find(:whatever) %>
. . .
<% end %>
Is there a common model that's being rendered in the main views that you could delegate the variable access to?
<%=h #model.variable %>