rails 3 json encode for consumption in javascript - ruby-on-rails

I know that to_json is deprecated and as_json is giving me problems.
This line works fine, but to_json is deprecated:
new IS.Presentation(<%= raw(#course_step.step.step_presentation.step_presentation_files.map { |item| {'url' => item.slide.url, 'title' => item.title}}.to_json) %>)
Any ideas?

ActiveSupport supports JSON. You can see here:
ruby-1.9.2-p136 :003 > j = ActiveSupport::JSON
=> ActiveSupport::JSON
ruby-1.9.2-p136 :004 > j.encode({:team => "Celtics", :players => "20"})
=> "{\"team\":\"Celtics\",\"players\":\"20\"}"
ruby-1.9.2-p136 :005 > j.decode("{\"team\":\"Celtics\",\"players\":\"20\"}")
=> {"team"=>"Celtics", "players"=>"20"}
So for you it would be:
new IS.Presentation(<%= ActiveSupport::JSON.encode(raw(#course_step.step.step_presentation.step_presentation_files.map { |item| {'url' => item.slide.url, 'title' => item.title}})) %>)

Related

Check values in a hash

I am working on a legacy Rails project that uses Ruby 1.8 .
I have an hash of key-value where value is a float number.
For example, my_hash = ['foo'=>12.20, 'bar'=>10.0]. How can I check if my_hash contains all zero values? e.g. ['foo'=>0, 'bar'=>0, 'whatever'=>0] or ['foo'=>0.0, 'bar'=>0, 'whatever'=>0.0].
I know I can loop through & check element one by one, but I just wonder is there a more elegant way?
use below code if my_hash is:
[{"foo"=>0.0, "bar"=>0, "whatever"=>0.0}]
my_hash.first.values.all?{|item| item.zero?}
or if my_hash is array, just:
my_hash.all?{|item| item.zero?}
Check all values in the hash are zero or not?
2.2.3 :006 > h={"foo"=>0.0, "bar"=>0, "whatever"=>0.0}
=> {"foo"=>0.0, "bar"=>0, "whatever"=>0.0}
2.2.3 :007 > h.values.all?{|a| a.zero?}
=> true
If it is an array of hash then
2.2.3 :001 > h = ['foo'=>0.0, 'bar'=>0, 'whatever'=>0.0]
=> [{"foo"=>0.0, "bar"=>0, "whatever"=>0.0}]
2.2.3 :004 > h[0].values.all?{|a| a.zero? }
=> true
OR
2.2.3 :014 > h
=> [{"foo"=>0.0, "bar"=>0, "whatever"=>0.0}]
2.2.3 :015 > h.first.values.all?{|a| a.zero?}
=> true
Any element is zero
2.2.3 :009 > h={"foo"=>0.0, "bar"=>2, "whatever"=>1.1}
=> {"foo"=>0.0, "bar"=>2, "whatever"=>1.1}
2.2.3 :010 > h.values.any?{|a| a.zero?}
=> true
2.2.3 :011 > h={"foo"=>0.2, "bar"=>2, "whatever"=>1.1}
=> {"foo"=>0.2, "bar"=>2, "whatever"=>1.1}
2.2.3 :012 > h.values.any?{|a| a.zero?}
=> false

simple_format changes the text itself

In Rails 3.0, the helper method simple_format changes the parameter itself.
I expected that it only returns the wrapped text.
2.0.0-p648 :001 > Rails.version
=> "3.0.20"
2.0.0-p648 :002 > s = "Hello"
=> "Hello"
2.0.0-p648 :003 > helper.simple_format(s)
=> "<p>Hello</p>"
2.0.0-p648 :004 > s
=> "<p>Hello</p>"
I checked with Rails 4.2 and it doesn't change the text.
Can someone please explain it?
Sam
The difference between implementations of this method in Rails 4.2 and Rails 3.0 is that in Rails 3.0 the passed string is modified (mutated by gsub!) and in Rails 4.2 it's not (it just returns a new modified string):
Rails 4.2:
2.4.0 :006 > s = "hello"
=> "hello"
2.4.0 :007 > simple_format s
=> "<p>hello</p>"
2.4.0 :008 > s
=> "hello"
The source code of different implementations can be found in the documentation

Mongoid not detecting change to localized field when setting field with xxxx_translations

Gem Versions
I am using Rails 3.2.18 and Mongoid 3.1.6.
The problem
I need to set a value for any locale in a localized field, not just the one that is currently in I18n.locale. I am setting it using title_translations['en'] = 'some title', but when doing this, mongoid does not detect the change (not dirty) and so nothing is saved.
The Model
I have a mongoid model with a localized field like the following:
class ApiMethod
include Mongoid::Document
field :title, type: String, localize: true
attr_accessible :title, :title_translations
end
Console Example
Below is an example of setting the title two ways, one as title = 'xxx' and one as title_translations['en'] = 'xxx' and the result of testing if the object has changed.
2.1.2 :083 > a = ApiMethod.first
=> #<ApiMethod _id: 5541cb17fb6fc67028000006, title: {"en"=>"Dataset Catalog"}>
2.1.2 :084 > a.title
=> "Dataset Catalog"
2.1.2 :085 > a.title_translations
=> {"en"=>"Dataset Catalog"}
2.1.2 :086 > a.title = 'new title'
=> "new title"
2.1.2 :087 > a.changed?
=> true ## YEA! - THIS IS CORRECT
2.1.2 :088 > a.changed
=> ["title"]
2.1.2 :089 > a.reload
=> #<ApiMethod _id: 5541cb17fb6fc67028000006, title: {"en"=>"Dataset Catalog"}>
2.1.2 :090 > a.title_translations['en'] = 'this is a new title'
=> "this is a new title"
2.1.2 :091 > a.title
=> "this is a new title"
2.1.2 :092 > a.title_translations
=> {"en"=>"this is a new title"}
2.1.2 :093 > a.changed?
=> false ## BOO! - THIS IS NOT CORRECT
Please Help!
Am I doing something wrong or missing something? Is it not possible to set a localized field value for a locale that is not the current I18n.locale value?
Thank you for your help!
Update
I just tried something else and this works. Instead of setting the title_translations for a specific locale, I tried setting the entire title_translations object:
2.1.2 :114 > a = ApiMethod.only(:title).first
=> #<ApiMethod _id: 5541cb17fb6fc67028000006, title: {"en"=>"Dataset Catalog"}>
2.1.2 :115 > x = a.title_translations.dup
=> {"en"=>"Dataset Catalog"}
2.1.2 :116 > x['en'] = 'this is a new title'
=> "this is a new title"
2.1.2 :117 > x
=> {"en"=>"this is a new title"}
2.1.2 :118 > a.title_translations = x
=> {"en"=>"this is a new title"}
2.1.2 :119 > a.title_translations
=> {"en"=>"this is a new title"}
2.1.2 :120 > a.changed?
=> true
2.1.2 :121 > a.title_change
=> [{"en"=>"Dataset Catalog"}, {"en"=>"this is a new title"}]
So it seems like if I replace the entire value for title_translations and not just a specific locale, the change is detected. While it is nice that this works, it is not ideal. Thoughts?

Array length not getting correctly

in view.html.erb page I have code like:
<%
str="D:\\projects\\curator\\java\\hpc"
no=str.count("\\")
splitstr=str.split(pattern="\\",no+1)
%>
After this I printed
<%= splitstr.length %>
It gives me the output as 9. But the splitstr has only 5 elements.
How is it happening.
You end up having four of ""(empty) strings in your array
use this instead..
splitstr=str.split("\\")
splitstr.length
1.9.3p385 :007 > str="D:\\projects\\curator\\java\\hpc"
=> "D:\\projects\\curator\\java\\hpc"
1.9.3p385 :008 > no=str.count("\\")
=> 4
1.9.3p385 :009 > splitstr=str.split(pattern="\\",no+1)
=> ["D:", "projects", "curator", "java", "hpc"]
1.9.3p385 :010 > splitstr.length
=> 5
1.9.3p385 :011 >
Im getting it right!

How to remove a key from Hash and get the remaining hash in Ruby/Rails?

To add a new pair to Hash I do:
{:a => 1, :b => 2}.merge!({:c => 3}) #=> {:a => 1, :b => 2, :c => 3}
Is there a similar way to delete a key from Hash ?
This works:
{:a => 1, :b => 2}.reject! { |k| k == :a } #=> {:b => 2}
but I would expect to have something like:
{:a => 1, :b => 2}.delete!(:a) #=> {:b => 2}
It is important that the returning value will be the remaining hash, so I could do things like:
foo(my_hash.reject! { |k| k == my_key })
in one line.
Rails has an except/except! method that returns the hash with those keys removed. If you're already using Rails, there's no sense in creating your own version of this.
class Hash
# Returns a hash that includes everything but the given keys.
# hash = { a: true, b: false, c: nil}
# hash.except(:c) # => { a: true, b: false}
# hash # => { a: true, b: false, c: nil}
#
# This is useful for limiting a set of parameters to everything but a few known toggles:
# #person.update(params[:person].except(:admin))
def except(*keys)
dup.except!(*keys)
end
# Replaces the hash without the given keys.
# hash = { a: true, b: false, c: nil}
# hash.except!(:c) # => { a: true, b: false}
# hash # => { a: true, b: false }
def except!(*keys)
keys.each { |key| delete(key) }
self
end
end
Why not just use:
hash.delete(key)
hash is now the "remaining hash" you're looking for.
Oneliner plain ruby, it works only with ruby > 1.9.x:
1.9.3p0 :002 > h = {:a => 1, :b => 2}
=> {:a=>1, :b=>2}
1.9.3p0 :003 > h.tap { |hs| hs.delete(:a) }
=> {:b=>2}
Tap method always return the object on which is invoked...
Otherwise if you have required active_support/core_ext/hash (which is automatically required in every Rails application) you can use one of the following methods depending on your needs:
➜ ~ irb
1.9.3p125 :001 > require 'active_support/core_ext/hash' => true
1.9.3p125 :002 > h = {:a => 1, :b => 2, :c => 3}
=> {:a=>1, :b=>2, :c=>3}
1.9.3p125 :003 > h.except(:a)
=> {:b=>2, :c=>3}
1.9.3p125 :004 > h.slice(:a)
=> {:a=>1}
except uses a blacklist approach, so it removes all the keys listed as args, while slice uses a whitelist approach, so it removes all keys that aren't listed as arguments. There also exist the bang version of those method (except! and slice!) which modify the given hash but their return value is different both of them return an hash. It represents the removed keys for slice! and the keys that are kept for the except!:
1.9.3p125 :011 > {:a => 1, :b => 2, :c => 3}.except!(:a)
=> {:b=>2, :c=>3}
1.9.3p125 :012 > {:a => 1, :b => 2, :c => 3}.slice!(:a)
=> {:b=>2, :c=>3}
There are many ways to remove a key from a hash and get the remaining hash in Ruby.
.slice => It will return selected keys and not delete them from the original hash. Use slice! if you want to remove the keys permanently else use simple slice.
2.2.2 :074 > hash = {"one"=>1, "two"=>2, "three"=>3}
=> {"one"=>1, "two"=>2, "three"=>3}
2.2.2 :075 > hash.slice("one","two")
=> {"one"=>1, "two"=>2}
2.2.2 :076 > hash
=> {"one"=>1, "two"=>2, "three"=>3}
.delete => It will delete the selected keys from the original hash(it can accept only one key and not more than one).
2.2.2 :094 > hash = {"one"=>1, "two"=>2, "three"=>3}
=> {"one"=>1, "two"=>2, "three"=>3}
2.2.2 :095 > hash.delete("one")
=> 1
2.2.2 :096 > hash
=> {"two"=>2, "three"=>3}
.except => It will return the remaining keys but not delete anything from the original hash. Use except! if you want to remove the keys permanently else use simple except.
2.2.2 :097 > hash = {"one"=>1, "two"=>2, "three"=>3}
=> {"one"=>1, "two"=>2, "three"=>3}
2.2.2 :098 > hash.except("one","two")
=> {"three"=>3}
2.2.2 :099 > hash
=> {"one"=>1, "two"=>2, "three"=>3}
.delete_if => In case you need to remove a key based on a value. It will obviously remove the matching keys from the original hash.
2.2.2 :115 > hash = {"one"=>1, "two"=>2, "three"=>3, "one_again"=>1}
=> {"one"=>1, "two"=>2, "three"=>3, "one_again"=>1}
2.2.2 :116 > value = 1
=> 1
2.2.2 :117 > hash.delete_if { |k,v| v == value }
=> {"two"=>2, "three"=>3}
2.2.2 :118 > hash
=> {"two"=>2, "three"=>3}
.compact => It is used to remove all nil values from the hash. Use compact! if you want to remove the nil values permanently else use simple compact.
2.2.2 :119 > hash = {"one"=>1, "two"=>2, "three"=>3, "nothing"=>nil, "no_value"=>nil}
=> {"one"=>1, "two"=>2, "three"=>3, "nothing"=>nil, "no_value"=>nil}
2.2.2 :120 > hash.compact
=> {"one"=>1, "two"=>2, "three"=>3}
Results based on Ruby 2.2.2.
If you want to use pure Ruby (no Rails), don't want to create extension methods (maybe you need this only in one or two places and don't want to pollute namespace with tons of methods) and don't want to edit hash in place (i.e., you're fan of functional programming like me), you can 'select':
>> x = {:a => 1, :b => 2, :c => 3}
=> {:a=>1, :b=>2, :c=>3}
>> x.select{|x| x != :a}
=> {:b=>2, :c=>3}
>> x.select{|x| ![:a, :b].include?(x)}
=> {:c=>3}
>> x
=> {:a=>1, :b=>2, :c=>3}
#in lib/core_extensions.rb
class Hash
#pass single or array of keys, which will be removed, returning the remaining hash
def remove!(*keys)
keys.each{|key| self.delete(key) }
self
end
#non-destructive version
def remove(*keys)
self.dup.remove!(*keys)
end
end
#in config/initializers/app_environment.rb (or anywhere in config/initializers)
require 'core_extensions'
I've set this up so that .remove returns a copy of the hash with the keys removed, while remove! modifies the hash itself. This is in keeping with ruby conventions. eg, from the console
>> hash = {:a => 1, :b => 2}
=> {:b=>2, :a=>1}
>> hash.remove(:a)
=> {:b=>2}
>> hash
=> {:b=>2, :a=>1}
>> hash.remove!(:a)
=> {:b=>2}
>> hash
=> {:b=>2}
>> hash.remove!(:a, :b)
=> {}
Hash#except (Ruby 3.0+)
Starting from Ruby 3.0, Hash#except is a build-in method.
As a result, there is no more need to depend on ActiveSupport or write monkey-patches in order to use it.
h = { a: 1, b: 2, c: 3 }
p h.except(:a) #=> {:b=>2, :c=>3}
Sources:
Hash#except from official Ruby docs.
Link to the PR.
Ruby 3.0 adds Hash#except and ENV.except.
You can use except! from the facets gem:
>> require 'facets' # or require 'facets/hash/except'
=> true
>> {:a => 1, :b => 2}.except(:a)
=> {:b=>2}
The original hash does not change.
EDIT: as Russel says, facets has some hidden issues and is not completely API-compatible with ActiveSupport. On the other side ActiveSupport is not as complete as facets. In the end, I'd use AS and let the edge cases in your code.
Instead of monkey patching or needlessly including large libraries, you can use refinements if you are using Ruby 2:
module HashExtensions
refine Hash do
def except!(*candidates)
candidates.each { |candidate| delete(candidate) }
self
end
def except(*candidates)
dup.remove!(candidates)
end
end
end
You can use this feature without affecting other parts of your program, or having to include large external libraries.
class FabulousCode
using HashExtensions
def incredible_stuff
delightful_hash.except(:not_fabulous_key)
end
end
in pure Ruby:
{:a => 1, :b => 2}.tap{|x| x.delete(:a)} # => {:b=>2}
See Ruby on Rails: Delete multiple hash keys
hash.delete_if{ |k,| keys_to_delete.include? k }
It's was great if delete return the delete pair of the hash.
I'm doing this:
hash = {a: 1, b: 2, c: 3}
{b: hash.delete(:b)} # => {:b=>2}
hash # => {:a=>1, :c=>3}
Try the except! method.
{:a => 1, :b => 2}.except!(:a) #=> {:b => 2}
This is a one line way to do it, but it's not very readable. Recommend using two lines instead.
use_remaining_hash_for_something(Proc.new { hash.delete(:key); hash }.call)
Multiple ways to delete Key in Hash.
you can use any Method from below
hash = {a: 1, b: 2, c: 3}
hash.except!(:a) # Will remove *a* and return HASH
hash # Output :- {b: 2, c: 3}
hash = {a: 1, b: 2, c: 3}
hash.delete(:a) # will remove *a* and return 1 if *a* not present than return nil
So many ways is there, you can look on Ruby doc of Hash here.
Thank you
This would also work: hash[hey] = nil

Resources