Is there some way to output an action in Rails template? Something equivalent to ASP.NET MVC Html.RenderAction ?
I need to render some stuff in sidebar and I don't want to put queries in partials or specific controller. So far I can think of only one way - put something into #stuff (by whatever means) instance var and let render find the proper partial or specify it explicitly. It would be better to be able to change only one file to change the contents of sidebar (as in ASP).
Yes, there is. You can add the "sidebar" partial to the application layout (in the app/views/layouts folder).
You can put the code that gets the "sidebar" variables in a before_filter in the ApplicationController
class ApplicationController < ActionController::Base
before_filter :sidebar_function
have a look at
http://guides.rubyonrails.org/layouts_and_rendering.html
especially read the subitem
http://guides.rubyonrails.org/layouts_and_rendering.html#using-content_for
I do not know ASP.net, however, I think Rails yield might be the solution. Here is a small example:
view:
<% content_for :one do %>
Test one
<% end %>
<% content_for :two do %>
Test two
<% end %>
<p>Hi</p>
application.html.erb
<%= yield :one %>
<%= yield %>
<%= yield :two %>
See Railsguides: http://guides.rubyonrails.org/layouts_and_rendering.html#understanding-yield
Related
I have an ERB view with two blocks:
<%= test_h1 do %>
<%= 'test1' %>
<% end -%>
<%= test_h2 do %>
<%= 'test2' %>
<% end -%>
where test_h1 and test_h2 are similar helpers, but one is defined in a helper file, while another via helper_method in a controller:
module TestHelper
def test_h1(&block)
link_to '/url' do
capture(&block)
end
end
end
class TestController < ApplicationController
helper_method :test_h2
def test_h2(&block)
helpers.link_to '/url' do
helpers.capture(&block)
end
end
end
test_h1 produces the expected result and test_h2 renders the inner template block first:
test1
test2
Why? What would be an idiomatic way to write test_h2 ?
I think both examples of views should be re-written as:
<%= test_h1 do %>
<% 'test1' %>
<% end -%>
<%= test_h2 do %>
<% 'test2' %>
<% end -%>
My understanding that '<%=' forces to render the output of the block to the output stream, that was not an intended behavior in these two examples
capture overrides current output buffer and just calls the block (which is still bound to other view context), thus override has no effect when called from controller because view_context is not the same context the view is being rendered in.
To work around contexts you can define your helper like so:
# in controller
helper do
def test_h3(&block)
# this will run in view context, so call `controller.some_func` to access controller instance
link_to '/url' do
capture(&block)
end
end
end
When using capture from your controller the output is appended to the page buffer, as a result the <%= from of your erb is outputting immediately to the page output.
To work around, you need to use <% instead within your test_h2 block. So to get the expected behavior in both cases, use this syntax:
<%= test_h1 do %>
<%= 'test1' %>
<% end -%>
<%= test_h2 do %>
<% 'test2' %>
<% end -%>
More info in this article: https://thepugautomatic.com/2013/06/helpers/
The idomatic way to do it in rails would be to move the test_h2 method to a concern and include that concern in controller as well as helper class.
Or else define test_h2 as helper_method in your controller class.
But generally methods that are needed in multiple places should be placed in concerns, and include those concerns wherever needed.
Also if you need methods for views, then include concerns or define your own methods inside helpers.
Refer Can we call a Controller's method from a view (as we call from helper ideally)?
How to use concerns in Rails 4
I want to display a random assortment of 6 tools from my database on my home page. I have created a Pages controller with a home action.
This is my Pages controller:
class PagesController < ApplicationController
def home
#tools = Tool.all
end
end
Then in my home.html.erb view I use the .sample method to grab random tools from my database as such(I repeat this 6 times using tool1, tool2, tool3, etc variables for each):
<% tool1 = #tools.sample %>
<%= image_tag tool1.tool_image.url(:medium) %>
<%= tool1.name %>
<%= tool1.description %>
I am wondering if there is a better way to do this. It seems that I have logic in my view and there must be a way to move that logic somewhere else? My model, controller, etc. How would one go about cleaning this code up so that it's good rails code? Or maybe this is good rails code and I just don't know it since I am a beginner.
Your controller doesn't need to extract everything from the tools_table, so I'd first remove the .all. Your example makes it seem like you just need 6 random objects from the database, here's one way to do that:
class PagesController < ApplicationController
def home
#tools = Tool.order("RANDOM()").first(6)
end
end
Then in your view you can just loop through those:
<% #tools.each do |tool| %>
<%= image_tag tool.tool_image.url(:medium) %>
<%= tool.name %>
<%= tool.description %>
<% end %>
In addition to Anthony's answer.
To clear up the view with some rails magic you can also add a partial to your app/views/tools called:
_tool.html.erb
Looking like:
<%= image_tag tool.tool_image.url(:medium) %>
<%= tool.name %>
<%= tool.description %>
And then change your view to
<%= render #tools %>
And Rails will know what to do if #tools is a collection of tools 😄
So I'm working on an open source project and due to different versions, there's the issue where I can't count on there being a controller for a view. Instead this email would be send out via a rake task for one version and a few others would done via a controller. Now you understand why I'm asking a bad practice question...
I have a layout for a view. Does anyone know a way to specify what the layout is for the view within the view. Some pseudo-code:
<%= extends 'layout/test_mailer` %>
<h1> Hey there! </h1>
And the layout would have the usual yield within it.
I hope I'm explaining the problem good enough.
<%= render partial: "hey_page", layout: "layout/test_mailer" %>
Check part 3.4.3 Partial Layouts at RailsGuides.
I think using yield and content_for should solve the problem. [Guides]
# my_layout.html.erb
<%= yield :mail_view %>
# my_mail_view.html.erb
<%= content_for :mail_view do %>
<!-- html -->
<% end %>
Of-course, if you are using params to get the layout, this would be a wrong answer.
Then, you can also use:
<%= render partial: "link_area", layout: "graybar" %>
You can use
//controller action
def index
render layout: test_mailer
end
//view, index.html.erb
<h1> Hey there! </h1>
//view, layout/test_mail.html.erb
<html>....layout for you test mail
<% yield %>
</html>
I have a pretty standard Rails 4 application at the moment with a number of static pages (home, about, contact etc) as well as the database backed pages. I want to include a html partial across most of the site but not on static pages (apart from the home page). I can get this working if I was stating just one page to exclude, for example the about page, using:
<% if !current_page?(about_url) %>
include the partial
<% end %>
I'm not sure how to write this to have a list of urls, i.e. about_url, contact_url etc. I tried something along the lines of:
<% if [about_url, contact_url, ...].!include? current_page
but maybe not surprisingly it didn't work.
Is there a way to achieve this within the erb itself without going back to the controller? (I'm thinking I'd have to create the array for each controller)
Thanks for any help.
-- Update --
I just tried (following the comment below):
<% if not [about_url, contact_url].include? request.original_url %>
<%= render partial %>
<% end %>
it doesn't appear to like this either. I'm not sure if my syntax if off again or it can't be done this way.
You can go about doing this in many ways, one of which can be:
<% if current_page?(controller: 'YOUR_CONTROLLER_NAME') &&
(current_page?(action: 'about') || current_page?(action: 'contact') || ... ) %>
include partial
<% end %>
I think it should work but your syntax is off.
<% if [about_url, contact_url, ...].!include? current_page
should be
<% if not [about_url, contact_url, ...].include? current_page
Or if you prefer (but I prefer "not" since it's more readable)
<% if ![about_url, contact_url, ...].include? current_page
However, for readability and testability you should perhaps put that logic in the application controller or in a helper.
Okay, thanks to the commenters I got it to work using the following:
<% if not [about_path, contact_path].include? request.path %>
<%= render 'layouts/minibar' %>
<% end %>
** the main points being to use *_path to compare against request.path.
when I render an partial for my model I'm using:
<%= partial #my_model %>
Automatically it looks for the file ..view/my_models/_my_model.html.erb
I really like this notation because it feels the right way!
My Problem:
Now I want a notation to automatically look up for the edit partial.
Is there a way? Until now I used
<%= partial 'edit' %>
This is ok, but I have a lot of subclasses for my model and I liked the way that it automatically looks up in the right subclasses view folder for the template.
Until know I have to look for the class for my model and then call
<% if #my_model.class == FirstSubClass %>
<%= partial 'firstsubclasses/_edit.html.erb' %>
<% elsif #my_model.class == SecondSubClass %>
<%= partial 'secondsubclasses/_edit.html.erb' %>
<% end %>
I prefer one line :) Any ideas?
Try:
<%= partial '#{#my_model.class.name.tableize}/_edit.html.erb' %>
tableize is a method of ActiveSupport::Inflector, which includes some other cool naming manipulation methods.