My scenario is that, some user who has the font_user role can use font, but others can't.
In ckeditor/config.js, I can't get any variable from Rails. How do I achieve this?
I have tried something like this:
Modify config.js to config.js.erb.
Add the following code.
<% current_user.has_role?(font_user) %>
XXXXX
<% else %>
XXXX
<% end %>
and I added the following method in application_controller.rb:
helper_method :current_user
But it seems config.js.erb can't get the current_user variable.
This is because asset JavaScript is compiled ones. Not each time a view is rendered. You should make use of unobstructive JavaScript. For example:
View example:
<div class="ckeditor" data-ckeditor-font="<%= current_user.has_role?(font_user) %>"></div>
Alternatively (not checked):
You could also use the #content_tag for this, although you have to check how to exactly pass along the data attributes. If I'm not mistaken:
<% data = {
'ckeditor-font': current_user.has_role?(font_user),
# other data...
} %>
<%= content_tag :div, class: 'ckeditor', data: data %>
But I currently don't have the setup to test the above code. So you'll have to check it yourself.
Than in your asset JavaScript (CoffeeScript):
initCkeditor = (element) ->
fontUser = element.dataset.ckeditorFont == 'true'
# further CKEditor initialization code...
document.addEventListener 'turbolinks:load', ->
document
.querySelectorAll '.ckeditor'
.forEach initCkeditor
If you don't set the data-ckeditor-font attribute the code still works. Since element.dataset.ckeditorFont would return undefined, and undefined == 'true' is still false. (Keep in mind that the CoffeeScript == equals JavaScript ===.)
See:
Working with JavaScript in Rails: Unobtrusive JavaScript
The Asset Pipeline for more info about the asset pipeline.
Using data attributes for more info about data attributes.
Related
In Rails 3.1 it is not possible to access controller instance variables in an asset js.erb or coffee.erb file using syntax such as <%= #foo %>, where #foo is set in the controller. So then the question is what are the best ways for passing controller variables to CoffeeScript or JavaScript assets.
This question has kind of been asked in multiple convoluted forms on the forum, but my point in asking it again is to have a place where all recommendations are gathered together, and the code supplied is simple and readable. Also note that I'm specifically referring to assets and not view response files.
a couple of ways I have done this in the past
put the data in hidden fields, access the data in js/coffee
# single value
<%= hidden_field_tag "foo_name", #foo.name, { :id => "foo-name" } %>
$('#foo-name').val();
# when the 'value' has multiple attributes
<%= hidden_field_tag "foo", #foo.id, { :id => "foo", "data-first-name" => #foo.first_name, "data-last-name" => #foo.last_name } %>
$foo = $('#foo')
console.log $foo.val()
console.log $foo.data("firstName")
console.log $foo.data("lastName")
another option: load data into js data structure in erb, access it from js/coffee
<% content_for(:head) do %>
<script>
window.App = window.App || {};
window.App.Data = window.App.Data || {};
window.App.Data.fooList = [
<% #list.each do |foo| %>
<%= foo.to_json %>,
<% end %>
];
</script>
<% end %>
# coffee
for foo in window.App.Data.fooList
console.log "#{foo.id}, #{foo.first_name} #{foo.last_name}"
I am not a big fan of constructing javascript data from ruby in erb like this, something about it just feels wrong - it can be effective though
and another option: make an ajax call and get the data on-demand from the server
I am also interested in other ideas and approaches
There is a really nice rail cast and quite recent (feb. 2012) about this specific topic:
#324 Passing Data to JavaScript
It shows 3 ways: a script tag, a data attribute, and the Gon gem.
I think house covered all the available techniques. I would only mention that using an AJAX call is best used when you have a large volume of data, dynamic data or combination of both.
Rather than use a hidden field I chose to add a data attribute to the container div which jquery can pick up.
<div class="searchResults" data-query="<%= #q %>"></div>
then the jquery to access it
url: "/search/get_results?search[q]=" + $(".searchResults").data("query") + "&page=" + p
I feel this is the cleanest way to pass data to javascript. After having found no way to pass a variable to a coffee script file with the rails asset pipeline from a controller. This is the method I now use. Can't wait till someone does set up the controller way with rails that will be the best.
In the controller:
#foo_attr = { "data-foo-1" => 1, "data-foo-2" => 2 }
In the view (HAML):
#foo{#foo_attr}
In the CoffeeScript asset:
$("#foo").data("foo-1")
$("#foo").data("foo-2")
In situations where your javascript data gets out of hand, using the gon gem is still the preferred way to go in rails, even in 2015. After setting up gon, you are able to pass data to your javascript files by simply assigning the data to the gon object in rails.
(Gemfile)
gem 'gon'
(controller)
def index
gon.products = Product.all
(layouts)
<%= include_gon %>
(public/javascripts/your_js_can_be_here.js)
alert(gon.products[0]['id');
(html source automatically produced)
<script>
window.gon = {};
gon.products = [{"created_at":"2015", "updated_at":"2015, "id":1, "etc":"etc"}];
You can read more verbose implementation details on Gon or the two other rails-javascript channels from Ryan Bate's screencast.
http://railscasts.com/episodes/324-passing-data-to-javascript
You can edit and add variables to the params array in the controller then access them in the response.js.erb. Here's an example with params[:value]:
def vote
value = params[:type] == "up" ? 1 : -1
params[:value] = value
#public_comment = PublicComment.find(params[:id])
have_voted = #public_comment.evaluators_for(:pub_votes_up) << #public_comment.evaluators_for(:pub_votes_down)
unless have_voted.include?(#current_user) # vote
#public_comment.add_or_update_evaluation(:"pub_votes_#{params[:type]}", value, #current_user)
else # unvote
#public_comment.delete_evaluation(:"pub_votes_#{params[:type]}", #current_user)
params[:value] = 0
end
respond_to do |format|
format.js # vote.js.erb
end
end
And here's an example accompanying response.js.erb
button = $('<%= ".pub#{params[:type]}_#{params[:id]}" %>')
label = button.find('strong')
<% comment = PublicComment.find(params[:id]) %>
label.html('<%= comment.reputation_for(:"pub_votes_#{params[:type]}").to_i %>')
<% if params[:value] == 1 %>
button.addClass('btn-success')
<% elsif params[:value] == -1 %>
button.addClass('btn-danger')
<% else %>
if button.hasClass('btn-success') { button.removeClass('btn-success') }
if button.hasClass('btn-danger') { button.removeClass('btn-danger') }
<% end %>
I'm using middleman to generate a static webpage. I need to add a consistent but understandable string to all urls so I can understand how users navigate on the page.
Now i do it like this
<% link_to '/'+?button=navigation , class: 'logotype', itemprop: 'url' do %>
...
<% end %>
I would prefer not having to manually add all the parameters but rather just use something that's already there, like a scope or something. I was thinking about using the name of the template file for example. The url is not unique enough.
Any suggestions?
The standard way of doing this would be to write a helper method that encapsulates your functionality:
<%= link_to_as_nav('/', class: 'logotype', ...) do %>
...
<% end %>
Then write a helper method:
def link_to_as_nav(url, options)
link_to(url + '?button=navigation', options)
end
This is the naïve approach and won't account for a url argument that already has parameters added, but that's something you can work to fix.
i am totally new to rails programming... i used the request.path to get the current url and display it in all my views by specifying it in applications.html.erb. It is returning the entire path and i want to display it as a link... so i use
link_to to specify it as url..now here is what i want to do.. the url returned will be in the format path1/path2/path3..... i want to display it as path1>path2>path3 and as a link such that when the user clicks path1, it should take him to path 1 and so on...
this is the code i gave in html.erb file
but i get an error that says undefined method.... what should i do to accomplish that??
You could split the request.path on / and then build up the various links, but that could get really cluttered for deeply nested paths. I think a better approach would be to use something like breadcrumbs_on_rails and declare your breadcrumbs explicitly and render them in a partial or helper method. I think you could also use some Rails filter magic to have action names breadcrumbed automatically, but making the breadcrumbs explicit forces you to think about your site and your users more than programmatically vomiting out a string of links of unknown length.
You can do like this:
<% path = request.path %>
<% links = path.split('/') %>
<% ll="/" %>
<% links.each do |l| %>
<% ll += (l+'/') %>
<%= link_to l,ll %> >
<% end %>
Is there any standard or emerging standard to document the parameters that can be passed into a Rails partial ?
When _my_partial.html.erb expects a title and an elements local var passed with render 'my_partial', title: t, elements: e, there must be a common way to document their names, expected types and roles, without reading the whole partial code. Something like RDoc or Tomdoc for methods and classes. Isn't there ?
Edit: I've found a post whose author advocates initializing parameters with <% var ||= 'default_val' %> in the first lines of the partial, which is indeed a safe practice and a kind of in-code doc. Is there really no comment/parameter-declaration solution for this ?
At the beginning of your partial, simply call all the variables that are referenced.
# _my_partial.html.erb
<% title %> <--- first line of file
<% elements[0] %>
<h3><%= title %></h3>
<% elements.each do |element| %>
<p> etc ... </p>
Reasons why this is good for your project:
it does not rely on comments or non-code files
any developer on the project can quickly find out which variables are needed by looking at the top of the file in question
by calling the variables, you ensure that a missing variable will result in an exception.
elements is called with square brackets because we also want it to blow up if it's not an enumerable, right?
The practice of using <% var ||= 'default_val' %> is actually unsafe because it allows bugs to hide. You want your code to immediately blow up the moment something isn't done right. And if these variables should be passed, then you want the code to blow up when they're not there.
<li<% if #flits.first == flit %> class="first" <% end %>>
I created css for #flits_list and #flits_list :hover in application.css in Rails 3 but I would like the first flit in the list (flits_list.first) to have different css so I created a class, but this code returns the error
no method error in home#index. you have a nil object when you didn't expect it! You might have expected an instance of array. the error occurred while evaluating nil.first
Any help would be greatly appreciated.
The problem is that #flits is nil, presumably because your all_flits method is returning nil.
However, I'd recommend not putting that logic in the view, breaking up a tag like that. You have several options to make it cleaner:
Option 1: Use the CSS pseudo-class first-child like so:
li:first-child {
...
}
This has the advantage of not requiring any back-end logic or special markup. The only downside is that it has spotty older browser support, e.g. IE6.
Option 2: Use the Rails tag helpers.
<%= content_tag :li, :class => #flits.first==flit?"first":"" %>
Option 3: Tuck it away in a helper method
<%= li_for_flit %>
Then in the helper:
def li_for_flit
#spit out your tag here
end