Ruby version: 2.3.1
Rails version: 5.0.5
I am using Google's dataLayer to record ecommerce events in my site. We are in the middle of an upgrade from rails 4 to 5 and I'm running into a wall with one of my rails helpers. I use a helper to generate a product_list and inject it into the view so I can send it to the dataLayer.
In rails 4 the dom reflects what I write in the helper, including the quotes I need to include for the format. In rails 5 however, the quotes are being converted to unicode and I can't figure out why or how to avoid this. This is not happening when I bind on the method in the terminal, it's only happening when it is loaded in the dom. I've tried adding sanitize(), .html_safe, converting this to a hash and converting this to JSON and nothing is working.
Right now it is working on rails 4 like this:
def foo
result += "'var1':'#{item.id}',
'var2':'#{item.title}',
'var3':#{item.price}},{"
result
end
end
What I get in the DOM:
'products': [{
'var1':'result1',
'var2':'result2',
'var3': 'result3'
}]
What is being returned on the DOM in rails 5:
'products': [{
'var1':'result1',
'var2':'result2',
'var3': 'result3'
}]
Not sure where you called html_safe, I quickly added this to a view I had in Rails 5 to attempt to replicate and here are my results:
View Helper
module HomeHelper
def result
"{'var1':'test'}".html_safe
end
end
View
<h1>Home#index</h1>
<p>Find me in app/views/home/index.html.erb</p>
<%= result %>
Generated Page
<h1>Home#index</h1>
<p>Find me in app/views/home/index.html.erb</p>
{'var1':'test'}
Related
I am saving a small JSON fragment in the database as follows but am stuck retrieving the data in a usable way.
In this app, Rails is getting the JSON via a fetch AJAX call, and successfully saving the following in the decor field:
{"drapes": "red", "table": "wood", "candles":"true"}
In the Rails console, this comes out as expected:
> p = Party.last
=> ...
> p.decor
=> "{:drapes=>\"red\", :table=>\"wood\", :candles=>\"true\"}"
decor is a (datatype) text field in SQLite at the moment. I've used PostgreSQL before for JSON but don't want to go there right now on this project and given the official doc reference (below), should be able to manage without any additional gems.
Here's the model (party.rb) as recommended by https://api.rubyonrails.org/classes/ActiveRecord/AttributeMethods/Serialization/ClassMethods.html:
class Party < ApplicationRecord
serialize :decor, JSON
end
And here's the relevant action in the controller (party_controller.rb):
def create
#party = Party.new(party_params)
#party.save
end
So all good until I actually want to to extract the decor and (for example) show it in a view template. With the following (in parties/index.html.erb)...
<p>
<%= p.decor.drapes %>
</p>
... I get:
NoMethodError in Parties#index
undefined method `drapes'
p.decor is obviously coming out of the model as the wrong data type but despite various experiments in the console, I can't see how to extract the JSON values using their keys.
I am using a lynda.com tutorial for Ruby on Rails. The very first instance of creating and using array instance variables does not work. At first I thought it was that #array might have become a reserve word in the newer 5.0 version of rails that I am using, but changing it did not cause the "nil" (undefined) error to go away.
What is wrong with Ruby Rails 5.0? It is refusing to define instance variables and to pass them to the appropriate template.
This is extremely aggravating, since rails is not behaving as documented (i.e. RAILS IS BRAIN DEAD OUT OF THE BOX).
****************
demo_controller.rb
class DemoController < ApplicationController
def index
render('hello')
end
def hello
#zarray = [1,2,3,4,5] <------------ this is defined
end
def other_hello
render(:text => "Hello EVERYONE!")
end
end
******************
hello.html.erb
<h1>Demo#hello</h1>
<p>Hello World!</p>
<%= 1 + 1 %> <------ works
<% target = "world" %>
</br>
<%= "Hello #{target}" %> <----- works
</br>
<% #zarray.each do |n| %> <---- line 10. Rails claims that #zarray is
not defined
<%= n %></br>
<% end %>
ActionView::Template::Error (undefined method `each' for nil:NilClass):
I copied and ran your code and it worked fine. I guess it could be down to the fact that controllers should as a rails convention be pluralized, and your controller is called DemoController and perhaps you've called demoS#action somewhere? So, generate a new controller from your terminal called:
DemosController
with the generator:
rails g controller Demos
And copy paste everything from the old controller to the new controller.
And in your routes.rb you need to first make sure you have the correct resources :demos (the name of your model) which will give you the standard RESTful resources (index, new, create, etc), but as your 'hello' method is not a part of the RESTful api, you need to create a custom route for that:
get 'hello' => 'demos#hello', :as => :hello
get = HTTP method
'hello' = The URL you want to hello.html.erb to be reachable on: localhost:3000/hello
'demos#hello' = demos is the DemosController and #hello is the action in the controller.
':as => :hello' (_path)is the named helper you can call in a link_to on any page for instance: link_to hello_path.
I am new to Ruby and Rails. I tested using a plain STRING instance variable, and THAT got passed from my controller to my template, so the issue was the array definition. Apparently the older form of array definition that was in the tutorial that I was using no longer works in the version of rails and ruby that I am using.
I am using Ruby on Rails 5.0.1 with Ruby 2.2.4p230 (2015-12-16 revision 53155) [i386-mingw32] on Windows (rails/ruby compatibility is kosher).
#zarray = [1,2,3,4,5] <-- the array is not defined when passed to template
#zarray = Array.new << 1 << 2 << 3 << 4 << 5 <-- this works
It is a bit distressing that Ruby does not even BOTHER to complain about the format of the array definition. It just DOES NOTHING (i.e., refuses to initialize the array).
In the template:
<% #zarray.each do |n| %>
<%= n %></br>
<% end %>
I should add that #zarray = {1,2,3,4,5] works if you use it after #zarray = Array.new
In other words, at some point in the evolution of Ruby, EXPLICITLY classing arrays was introduced? It is not always clear in the documentation. The earlier tutorial I was using does NOT explicitly class the array.
The problem seems to be in the current RAILS version (5.0.1) that I am running. I has done SOMETHING to destroy the ability of Ruby to create an array using array literal syntax. When I run array definitions with literal syntax in IRB, I have no problem creating them. So Ruby is fine. It is a serious BUG in the 5.0.1 version of rails. So I think I should report it.
Welcome to Git (version 1.8.1.2-preview20130201)
$ irb
irb(main):002:0> service_mileage = [5000,15000,30000,60000,100000]
=> [5000, 15000, 30000, 60000, 100000]
irb(main):003:0> service_mileage[0]
=> 5000
irb(main):004:0> service_mileage[2]
=> 30000
irb(main):005:0>
In my Rails 3.2 app (Ruby 1.9) I get following error when using path helpers in Coffeescript.
undefined local variable or method `new_user_session_path'
In my partial _usermenu.html.haml that works fine:
= link_to t('user.login'), new_user_session_path
In my app/assets/javascripts/metamenu.js.coffee.erb that throws above error:
$.get("<%= new_user_session_path %>")
Isn't it possible to use x_path and x_url helpers in coffeescript erb's?
This is because you are not within the view context inside of your assets. Adding an erb extension to the file doesn't change this, it simply allows you to evaluate embedded ruby.
If this is a one-off scenario, your best bet is to simply use the string itself.
$.get("/sign_in")
If you really wanted to you could create a partial that output a script tag that output your helper methods into js variables and access them that way.
# in your layout
<%= render 'url_helpers' %>
# in app/views/layouts/_url_helpers.html.erb
<script>
window.new_user_session_path = "<%= new_user_session_path %>";
# add more if necessary
</script>
# in your coffeescript
$.get(#new_user_session_path)
Also worth keeping in mind that this will obviously never work for member routes where your passing an instance of a model to the url helper as that is definitely not available to coffeescript. Remember, in production assets are precompiled so you can't use anything dynamic. For that you can only really rely on setting up actions in your controller to respond to JS calls.
Old post, but still accessible from Google.
In rails 4 (and certainly at least 3 too) you can use the route helpers to insert your js files easily:
assets/javascript/my_file.js.coffee.erb
<% self.class.include Rails.application.routes.url_helpers %>
window.index_route = '<%= index_path %>'
I've seen a lot of questions around this topic but no definitive solutions. I have a Rails 3.2 app that leverages ERB/slim and Coffeescript/EJS/Backbone. I inherited this codebase so some of these peripherals are a little over my head.
Problem
My venue view has a section that displays tips that were submitted to the venue. The list of tips has a "sort" function facilitated by JavaScript. The associated CoffeeScript file has event listeners for clicks on links for "recent" and "popular". On click, the JS does some work and utilizes Rails scopes to resort the list. I'm building out this tips list to include a little more data, specifically including the Rails helper time_ago_in_words. The original code updated the div containing the tips using a JST/EJS template in the Javascripts/templates asset directory.
These are the specific problems I encounter:
If I add .erb to the file chain (after updating the EJS interpreter to look for a different evaluation and interpolation pattern as to not conflict with ERB), I can evaluate basic Ruby expressions. The partial, however, fails to have access to the same tip variable that the JavaScript references. I know this is because Rails is server side and JS is client side. Consensus seems to be no, but is there a way to get that data to Rails?
While basic Ruby expressions can be evaluated (Time.now, for example), Rails helpers such as time_ago_in_words fail, complaining that the method is undefined for the class, though I am absolutely passing in the proper date object. Can Rails/helpers not be evaluated in this .EJS.ERB chain?
I can circumvent all of these problems if there is a way to reference the original ERB/slim partial used on load after the sort is performed. Is this possible? Right now the Coffeescript file called uses render and JST to call on the EJS template. Is it possible to somehow reference the original partial but with the updated sort?
Here's the relevant code.
##show.html.erb (venue)##
#tips
p.sort.span4
| Sort by:
= link_to 'Recent', '#', class: 'selected', id: 'sort-tips-recent'
| |
= link_to 'Popularity', '#', id: 'sort-tips-popularity'
#tip-list
= render resource.tips.by_recent
##tip_list_view.js.coffee##
class CS.TipListView extends Backbone.View
el: "#tip_module"
events:
"click #sort-tips-recent": "sortByRecent"
"click #sort-tips-popularity": "sortByPopularity"
initialize: ->
console.log("ERROR: View must be initialized with a model") unless #model
#model.bind('reset', #render)
render: =>
tips = #model.map (tip) -> JST['templates/tip'](tip: tip)
#$('#tip-list').html(tips.join("\n"))
sortByRecent: (e) ->
e.preventDefault()
#model.enableSortRecent()
#updateSelectedFilter('recent')
sortByPopularity: (e) ->
e.preventDefault()
#model.enableSortPopularity()
#updateSelectedFilter('popularity')
updateSelectedFilter: (sort) ->
#$('p.sort a').removeClass('selected')
#$("p.sort a#sort-tips-#{sort}").addClass('selected')
##tip.jst.ejs.erb (called from tip_list_view.js.coffee after sort change##
<div class="tip">
<p class="tip-author">
<$= tip.get('user').username $>
</p>
<p class="tip-timestamp">
Eventually, time goes here
</p>
<p class="tip-likes pull-right">
<$= tip.upvoteCountText() $>
</p>
<p id="<$= tip.domId() $>">
<$= tip.get('text') $>
<$ if(tip.get('can_upvote')) { $>
upvote
<$ } $>
</p>
<div>
Definitely at a loss here - any and all help is greatly appreciated. Let me know if there is any other detail or code I can provide for background. Thanks in advance!
With your ejs.erb, Rails is generating the template, but has no idea what you will use it for. Then your Backbone app is fetching the tip from Rails via ajax, and populate the model accordingly. Then it's your backbone app that populates and renders the template. Rails cannot chime in here, at least not in this configuration where backbone expects json and then renders the template. Everything is happening in the front-end.
The only thing you can do is ask Rails to give you the result of your helpers inside the json. I am guessing you have a Tip.rb model and it should implement:
include ActionView::Helpers::DateHelper
...
def as_json(options = {})
{
:name => self.name,
... (all the model attributes that you want to expose)
:date_age => time_ago_in_words self.created_at
}
end
That being said, I would def use a client side solution, also because: http://rails-bestpractices.com/posts/105-not-use-time_ago_in_words
I am creating locale files for internationalization in a rails app, and have a url that I want translated with tags included , for example
html.erb
<%= t(foo.bar.xxxx) %>
yml file
foo: bar:
xxxx: "xxxx"
result
< ;a href=
"/info/index.html"> ;xxxx</a> ;
which breaks my links. I do not have an h on the ruby part, so shouldn't this work?
Or should I just not have html tags within the yml file?
Rails version is 3.0.1
Ruby version is 1.8.7 p249
Your HTML YAML keys need to have a _html suffix:
foo:
bar:
xxxx_html: "<strong>Some HTML Here</strong>"
Doing this Rails will mark the string has html_safe and will render out the HTML instead of converting it to > and <.
You need to reference it with the full key name as well, Rails doesn't automatically see the _html suffix when you call xxxx.
<%= t 'foo.bar.xxxx_html' %>
Rails is preventing injection attacks by preventing model data from being displayed as actual markup. The raw function prevents that conversion.
Does
<%= raw t(foo.bar.xxxx) %>
work?