Rails erb templating, link element visibility to action in yield? - ruby-on-rails

In application.html.erb file, can I link HTML elements visibility to actions that are inside the <%= yield %> tag ?
For example if I have a header element and want to display a text there if <%= yield %> is displaying a specific action?

You can use the current_page? helper to determine if you're on a specific page (as identified with the given path parameters, etc.) and branch accordingly.
Or, if you need a more broad stroke you can use controller_name and/or action_name to get the current controller's name and the current action's name and branch accordingly.
Lastly, you can inspect params[:controller] or params[:action], which are sometimes more revealing than the above.

Related

Never use Turbolinks to load a specific route

I know that I can use the data-no-turbolink attribute to ensure that a link (or many links) don't use turbolinks, but is there any way to ensure that a specific page will never be loaded via turbolinks?
I have a particular page that is broken when loaded via turbolinks, and instead of employing some hacks to fix this, I'd rather that this page just always load in the usual fashion.
I know I can add data-no-turbolink to all links going to this page, but then I'd have to remember to do this to every subsequent link to this page, which is pretty hacky.
Is there a better way?
To modify all new and existing URLs to remove turbolinks to a specific URL, read below:
Since you're wanting to always use "data-no-turbolinks" when linking to a specific page via link_to, you can modify the method to check the URL of its destination and set the data-no-turbolinks attribute.
Modify the link_to helper (be sure to replace ROUTE_url and ROUTE_path with the correct variables from your routes:
# application_helper.rb
def link_to(name, path, options = {})
no_turbolink_routes = [ROUTE_url, ROUTE_path] # Add URLs/PATHs here
if no_turbolink_routes.include? path
options['data-no-turbolinks'] = 'true'
end
super(name, path, options)
end
You can add the following code to your application's helper file. It will check the controller and action being called on the page, then return an HTML attribute if it matches.
# application_helper.rb
def no_turbolinks
"data-no-turbolinks='true'".html_safe if controller_name == "your_controller" && action_name == "your_action"
end
Then, in your application's HTML:
<body <%= no_turbolinks %>>
Ideally, this would only load on the specific page that you want it to; disabling turbolinks for that one page.

print line in rails only for a specific page

I am new in rails and have the following issue:
I have a view that renders from the layout across several pages, it is in fact a part of the header. I want to remove a specific line from the header and hide it only for one page. I have tried to add a condition in the view to check if the page rendered comes from a specific controller/action but it doesn't work. what is the best practice for this case?
thanks
Just keep a instance variable in controller action and set is as true. Use this variable to with conditions to include/exclude specific code.
controller action
#include = true
view
if #include.present?
//place the line which should be excluded
end
I've asked a very similar question, and you are allready on a good way:
Use a condition like
<% if current_page?(view_path)==false %>
<your line>foobar</your line>
<%end%>
In the view you can access the controller from params[:controller] so you could have
<% if params[:controller] == foo %>
<p>conditionally shown</p>
<% end %>
Its not always best practise to use params directly inside the view though...

What is the difference between render and yield in Rails

Can someone explain the difference between "<%= render %>" and "<%= yield %> with <% content_for :partial do %>/<% end %>"? specifically how the routing changes when switching from one to another, the benefits of using one over the other, when is it practical to use one over the other. THIS is the closest explanation I have found, but isn't quite clear enough for me.
I have been trying for several days to wrap my head around this, but it seems that each configuration I try either comes close, or errors out.
If theres are three views, aaa and bbb and ccc, and each has an index.html.erb, but bbb and ccc have a _content.html.erb partial (signified by the underscore) how can you accomplish getting the bbb or ccc partial in aaa using either render or yield?
The following works:
aaa's index.html.erb :
<div">
<%= render 'bbb/content' %>
</div>
and bbbs _content.html/erb :
<p>Content from bbb.</p>
BUT this does NOT:
aaa's index.html.erb :
<div">
<%= yield :container %>
</div>
and bbbs _content.html/erb :
<% content_for :container do %>
<p>Content from bbb.</p> ### viewed in aaa
<% end>
and cccs _content.html.erb would have nothing, or the content_for, but I still dont get aaa's index.html to be populated with content.
If I use the render, I can explicitly place the content in. But I thought that the benefit of using the yield :whatever would allow me to choose what to populate it with, and I can't get it to populate anything as soon as I change it from render to yield. Do I also have to update the routes file? If so, how do I choose which one to populate it with? Does that mean its in the controller? and needs an action?
I also have though that it depends on which file is initially routed to, but like I said, I think I need to understand the difference between the two before I can begin to use the partials to my advantage.
First of all, yield is ruby, render is rails. Usually one uses a common layout for the application whose inner content changes according to action/context. The problem usually lies in defining where our layout ends and context-specific template begins. Take, for instance, the HTML title tag. Let's say you have an application called Cities. In most cases, you want your page title to be "Cities" all the time. But, if you're for instance, inside Amsterdam page, then you would like the have "Amsterdam" as your page title.
# application.html.erb
<html>
<head>
<%= content_for?(:page_title) ? yield(:page_title) : "Cities" %>
......
# city/index.html.erb
<% content_for :page_title do %>
<%= #city.name %>
<% end %>
<div class="bla"...
Within Rails you usually define your application title in your application layout. One strategy for changing the page title would be to use content_for in the specific cities template and change accordingly.
Render, on the other hand, accomplishes different rendering strategies. Straight. When you call render, it renders. content_for/yield doesn't render automatically, it is stored somewhere and then fills up the missing spots in the due places. So, you can think of it as more as a "store/search/replace" in comparison to render, which just plain renders.
Good rule of thumb to use one over the other is: if the template you are writing needs to present different information per context, strongly consider using content_for.
yield
Ruby code (Proc class) and takes your block and does what it is supposed to do with it. Yield is also fast compared with other Ruby based ways of doing the same thing.
I'd assume (and I only) use it in the layouts because it's quick and I mindlessly do what's normal in Rails. yield is also used to pass content to a specific spot in your layout. I often have <%= yield :head %> in the head, just above the head tag, so that I can pass random weirdness that sometimes comes up.
Common Uses:
Mostly just used in layouts
(if you are fancy/inclined to do so in a Model) as a true Ruby Proc
statement.
render
Rails code that you pass arguments to that, as the docs say, "Renders the content that will be returned to the browser as the response body". partials, actions, text, files...etc.
Common Uses:
Used in both views and the controller.
When your controller method exits, it renders the associated file. So the edit controller renders edit.html.erb. It uses the specified layout or application.html.erb if none is specified.
Within your layout file, when you call yield it will fill in the information from your render. If you call yield with a parameter, it will look for a content_for section in your render file matching that parameter. I'm not completely sure, but I don't think you can call yield from outside of your layout file, and I don't think it will fill in any information except that found in your render file.
Anywhere in your layout file or your rendered file, you can render a partial by calling render with the partial name minus the underscore.
I hope that helps.
Edit to answer question in comment:
yield and render perform similar functions however yield only looks in the render file whereas render specifies which file to render. Also, render outputs the entire file, but yield with a parameter can output just a subsection of the file.
Here's a visual to put them both in perspective:
The render method is called at the end of a controller action and orchestrates what block is passed to the method that is actually rendering the application.html.erb by yielding the passed block.
https://richstone.io/debunk/

rails access view name inside partial

I have a partial that I am using in different pages. I want to conditionally hide a certain div inside the partial based on the view that is rendering it.
I was thinking about creating a page specific javascript file that would look up the div and and hide it.
But, if there was a way to retrieve the view name / page name inside the partial it would be central to the partial and would not necessitate loading the same javascript file in multiple pages.
Does anybody know a way to do this inside a partial
While #wahaj's answer would work, if you want to do what you need in a central location, you could check the controller_name and action_name variables in the partial to determine the view you're in (e.g. controller_name == "services" and action_name == "show" would let you know you're in the Show view for the Service controller)
you can get the name of the currently-rendering partial from within a Helper method with the following :
controller.view_context.view_renderer.instance_variable_get('#_partial_renderer').instance_values['path']
You could send the style parameter as a local variable to the partial, varying the parameter depending on where you're calling from. Something like:
render :partial => 'xyz', :locals => {:style => 'display:none or display:block'}
and in the partial you could do:
<div style=<%=style%>></div>
simple solution , inside your partial check if you need to show partial or not
_partial_name.html.erb
<%= content_tag :div, :style=> "display : #{show_div? ? 'block' : 'none'}" do%>
html...or other stuff
<%end%>
and then in application helper
app/helper/application_helper.rb
def show_div? #you can set name of your div like 'show_sidebar_div?'
#decide either show this div or not
action_name == 'show'
end

How to do user content from CMS in Rails

I'm trying to build a CMS in Rails from scratch, and for showing the user generated pages I'm having trouble deciding exactly how to do it.
The way I have it right now, I have a controller named 'content' with a single action called 'show'. In routes.rb I have a rule that passes any name after the name of the website to the content controller, show action with parameter name.
For example, www.mysite.com/about_us would route to
:controller => 'content', :action => 'show', :page => 'about_us'
Inside the content controller, I do a find on the Pages model to locate the named page:
#markup = Page.find_by_name(params[:page])
And then in the show.html.erb view I use the raw helper to display the content:
<%= raw #markup.text %>
Does this method violate anything about the way I should do be doing things in Rails? Or is this an OK solution?
I ended up using the sanitize helper, by default it removes <script> tags which is essentially what you need to prevent XSS, as far as I understand. For those who have found this via a search, the only code that changes from what I described above is that in the view you change to:
<%= sanitize #markup.text %>

Resources