Problem with block helpers and JavaScript templates after Rails 3 upgrade - ruby-on-rails

I have an application I'm upgrading from Rails 2.3 to Rails 3 that uses a combination of helpers and JavaScript templates that is not working after the upgrade. I have the following code in a view partial:
<%= content_for :jstemplates do -%>
<%= "var serviceoverride='#{generate_template(customer_form, :serviceoverrides).html_safe}'" %>
<%= "var clientimage='#{generate_template(customer_form, :customer_images).html_safe}'" %>
<%= "var formula='#{generate_template(customer_form, :formulas).html_safe}'" %>
<% end -%>
That calls a generate_template helper:
def generate_template(form_builder, method, options = {})
escape_javascript generate_html(form_builder, method, options)
end
def generate_html(form_builder, method, options = {})
options[:object] ||= form_builder.object.class.reflect_on_association(method).klass.new
options[:partial] ||= method.to_s.singularize
options[:form_builder_local] ||= :f
form_builder.fields_for(method, options[:object], :child_index => 'NEW_RECORD') do |f|
render(:partial => options[:partial], :locals => { options[:form_builder_local] => f })
end
end
And the view partial is rendered from one of the standard controller views. The problem is that the JavaScript output on the rendered page is always HTML escaped and thus is directly rendered on the page. This worked correctly in Rails 2.3.x and obviously broke in Rails 3, I suspect with the change in behavior of <% %> block style helpers.
My problem is that I cannot get the jstemplates to render unescaped. I've looked into the changes in block style helpers and tried ensuring that all content generating blocks are using <%= %>, using the <%=raw %> function, adding .html_safe to strings and so on. It seems like I'm missing something basic.
Any help would be appreciated.
Chris

I found the answer. I apparently had the raw blocks in the wrong place. This change fixed it:
<%= content_for :jstemplates do -%>
<%=raw "var serviceoverride='#{generate_template(customer_form, :serviceoverrides).html_safe}'" %>
<%=raw "var clientimage='#{generate_template(customer_form, :customer_images).html_safe}'" %>
<%=raw "var formula='#{generate_template(customer_form, :formulas).html_safe}'" %>
<% end -%>

Related

Using a custom tag helper for ruby on rails with a bootstrap navbar

My problem is that I can't get this helper tag to display at all.
So in application_helper.rb I want to have a <% nav_link(name, path) %> tag helper to append bootstrap's .active class dynamically.
My code is the following:
def nav_link(name, path)
content_tag(:li, :class => active_class(path)) do
link_to name, path
end
end
def active_class(path)
(current_page?(path) ? "active" : "").html_safe
end
and I would like to use it like so
<% nav_link("Users", users_path) %>
My hunch is that there's a variable somewhere that's not properly sanitized. How do I fix this? Is the html_safe call necessary?
Unless it's a typo, you should use <%= nav_link("Users", users_path) %>.
Without =, nothing will be displayed
I think that your problem is that you have written <% nav_link(name, path) %> this executes the code but doesn't print anything.
It should be <%= nav_link(name, path) %>
I highly recommend this Gem, it will do exactly what you want.
https://github.com/vigetlabs/nav_lynx
And here is a method it provides:
<%= nav_link_to 'Page', my_path, {}, { :wrapper => 'li' } %>

Rendering content inside a partial via =yield

I'm creating an application with ruby on rails where I have an items/_item.html.erb. Inside the partial is a yield statement so i can add extra content as needed. In this case, I want to add a specific button to item depending on what view calls partial.
This is what I've tried and it renders the partial, but it does not render the block:
_item.html.erb
<%= yield if block_given? %>
<div>
<%= item.name %>
</div>
someview.html.erb
...
<% render(:partial => 'items/item', :collection => current_user.items do %>
<%= "HELLO" %>
<% end %>
...
I have also tried using content_for and some other stuff with no success. Is there a way to be able to render specific content inside a partial via yield? I'm currently using Rails3
EDIT:
I've found out that it's the :collection hash that makes it impossible insert the block.
Both of this pieces of code work:
<%= render :layout => 'items/item' do %>
Hello world
<% end %>
<%= render :layout => 'items/item', :locals => {:item => current_user.items.first} do %>
Hello world
<% end %>
This means that if i do a .each i could accomplish what I want but it would be ugly code. Anyone know a way around this?
content_for should work fine in this case. Here is the code I just double checked locally.
somewhere.html.erb
<% content_for :foobar do %>
fubar
<% end %>
_item.html.erb
<% if content_for? :foobar %>
<%= yield :foobar %>
<% end %>

How to merge multiple partial templates into one file?

I'm using Ruby on Rails 3 to create my web app.
I don't want to create a template file for each tiny partial template so I tried to merge them into one file using content_for method but it doesn't works.
My ERB template files are as follows.
layout/_fragments.html.erb: contains contents of some partial templates
<% content_for :twitter_checkbox do -%>
<% can_post_twitter = current_user && current_user.twitter_oauth %>
<% label_text = can_post_twitter ? "Post to Twitter" : "Set up your Twitter account" %>
<%= label_tag :twitter, label_text %>
<%= check_box_tag :twitter, 0, false, :disabled => !can_post_twitter %>
<%- end %>
<% content_for :other_content_of_partial_template do -%> # content of another partial template
...
layouts/application.html.erb
<!DOCTYPE html>
<html>
...
<body>
<%= yield %>
</body>
</html>
<%= render 'layouts/fragments', :formats => :erb %>
layouts/_form.html.erb
<%= form_for(#entry) do |f| %>
...
<%= content_for :twitter_checkbox %> # it shows nothing
<% end %>
What is wrong with this way?
Are there any other better ways to write multiple partial templates into one file?
I suppose you have run the _form partial before your main layout had the chance to run the _fragments partial, so when you display the fragments, they are not yet created.
The action is rendered before the layout, not after. Calling the _fragments from your action instead of from layout should make it clear whether this is the problem. At least, I believe so ;-)
You're missing the = sign in the second snippet which would tell Rails to display the returned text.
<%= form_for(#entry) do |f| %>
...
<%= content_for :twitter_checkbox %> # Note <%= - it should now show stuff
<% end %>

How do you find out what controller/action you are in via ruby code?

I have a different subheader partial I want to render dependent on where I'm at in my application. How do I go about determining where I'm at via ruby? Or do I need to parse the URL?
Example :
If I'm at my root level I want to use /home/subheader, if I'm in controller 'test' I want to render /test/subheader, etc... etc...
basically looking for this part:
(in my application view)
<%- if ############ %>
<%= render :partial => '/home/subheader' %>
<%- elsif ########### %>
<%= render :partial => '/test/subheader' %>
<%- else %>
<%= render :partial => '/layouts/subheader' %>
<%- end %>
Thanks
You can use current_page?
if current_page? :controller => 'home', :action => 'index'
do_this
end
or use the controller's method controller_name
if controller.controller_name == 'home'
do_that
end
If you're using this in a per-controller basis, you should probably need layouts or use different templates, rendering different partials depending in controller/action is a code smell.
P.S: You could also try to get the params[:controller] and params[:action] variables, but I am not sure if they are passed correctly if your route is non the standard /:controller/:action
A slightly easier way to manage this would be to use content_for. For example:
#app/layouts/application.html.erb
<html>
<body>
<h1>My Application</h1>
<%= yield(:subheader) || render(:partial => 'layouts/subheader') %>
<%= yield %>
</body>
</html>
This layout will first try to render the subheader content that was passed in from the view, otherwise it will render the partial 'layouts/subheader'. Then in each view that requires a custom subheader, all you have to do is:
#app/views/home/index.html.erb
<% content_for :subheader, render(:partial => 'subheader') %>
And in your other controller, you could use something completely different, like:
#app/views/other/show.html.erb
<% content_for :subheader do %>
<h2>A different subheader</h2>
<% end %>

remote_form_for doesn't call rjs template

So here is my form
<% remote_form_for([:admin, Page.new]) do |f| %>
<ol>
<li>
<%= f.label(:title) %>
<%= f.text_field(:title) %>
</li>
<li>
<%= f.label(:parent_page) %>
<%= f.select(:parent_page_id, Page.roots.map { |p| [p.title, p.id] }.unshift(["none", nil])) %>
</li>
</ol>
<div class="modal-controls">
<%= submit_tag("Save") %> or <%= link_to_function("cancel", "R.Pages.hideAdd();") %>
</div>
<% end %>
And my action
def create
#page = Page.create(params[:page])
#languages = Language.all
#languages.each do |language|
#page.page_languages.create(:language_id => language.id)
end
For some reason the submitted for does not call the create.js.rjs template, but instead tries to call create.html.erb, do i need some sort of extra setting with the form?
btw i am using rails 2.3.5
I can't remember the exact default behavior in rails, but have you tried putting a respond_to at the end of your controller action:
respond_to(:html, :js)
Hope this helps.
EDIT
I went back to check on the default behavior for Rails in respect to rendering views. Rails favors convention over configuration in this instance. The default behavior is that Rails automatically renders views with names that correspond to actions. You don't need the respond_to any more if you stick to this convention. Here is the documentation.
Just wanted to update my post with the correct info... glad you figured your problem out.
I had named my template create.rjs.js instead of create.js.rjs, thats why i didnt work

Resources