Rails Hash Format - ruby

Which is the preferred hash format for Rails? Or is one of them wrong?
User.create(:name => "John")
or
User.create(name: "John")
Can I do
User.create(:name "John")
or
User.create(name: => "John")

The ruby 1.9's way is to do User.create(name: 'John'). The older fashion is to do User.create(:name => 'John'). Other solutions will not works.

You just need to realise the semantics of the different symbols.
In here:
User.create(:name => "John")
You have a symbol :user mapped with linking operator=>.
In here:
User.create(name: "John")
You have linking operator :.
These two are wrong:
User.create(:name "John")
Here you have symbol and then no link from key to value at all.
This too:
User.create(name: => "John")?
You have two links once : and once =>.
I think your biggest issue is that you do not completely undertand the meaning of symbols in Ruby. Read here.

Use Ruby >= 1.9 syntax for hashes. Prefer { a: :b } over { :a => :b }.
If you want to study rails, I highly recommend a git repo(https://github.com/bbatsov/rails-style-guide), it can help you write good style rails code, hopefully useful to you.

Related

How to use a string to find a symbol in a hash

I have a string:
category = "cupcakes"
I need to see if this hash has that string, converted to a symbol, as a key:
products = {
:cupcakes => [{:title => "chocolate", :flavor => "chocolate"}, {:title => "summer special", :flavor => "pink cake"}],
:cookies => [{:title => "chocolate bliss", :flavor => "chocolate chip"}, {:title => "breakfast surprise", :flavor => "oatmeal raisin"}]
}
This one does not work because category is a string, not a symbol.
products.key?(category)
This one does not work because :cupcake is a unique symbol, and we are just creating another symbol.
products.key?(category.to_sym)
I think this comes from a misunderstanding of how symbols work. Every symbol with the same content is absolutely identical down to having the same object_id. Symbols with different content are always different. This is in contrast to strings where they may have identical content but a different object_id, or where one moment a string might contain one thing and the next it's completely different despite having the same object_id.
Ruby's object_id values are just what they say they are, "object identifiers", and are a way of saying "object number".
Now the string "cupcake" and the symbol :cupcake are not the same:
"cupcake" == :cupcake
# => false
If you do the conversion, they are:
"cupcake".to_sym == :cupcake
# => true
The real problem is you're expecting :cupcake and :cupcakes to be the same thing. Ruby doesn't understand English rules and semantics, so as far as its concerned those are two completely different things.
If you're using ActiveSupport you can do things like:
"cupcake".pluralize.to_sym == :cupcakes
# => true
That requires an additional library, but the good news is it comes with things like Rails by default.
In any case, the way you've defined your data you need to reference it as something like:
products[:cupcakes]
products["cupcake".to_sym]
products["cupcake".pluralize.to_sym]

Hash syntax strangeness [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Is there any difference between the :key => “value” and key: “value” hash notations?
What's the difference between this:
method: :delete
and this?
:method => :delete
I'm guessing it has to do with different versions of Rails but not sure. I have only worked in Rails 3.x.
They are completely equivalent, except the first can only be used since ruby 1.9 (and higher, of course).
In ruby 1.8 the hash syntax used the =>, also known as the hash rocket. You could put anything in front, and anything behind, but the thing in front is your key, behind the value. If you have a symbol as key, and a symbol as value, you would write:
:method => :delete
But you could also write
{ 1 => 'one', :2 => 'two', 'THREE' => 3 }
Now, for ruby 1.9.x, a new shorter syntax was introduced. Since most people use symbols as keys, you can now write:
method: :delete
Which is just a shorter/cleaner version. Also note that it is possible to mix both styles, which in some cases is needed.
E.g. in ruby 1.8 you would write:
{ :class => 'smthg', :'data-type' => 'a type' }
This would translate to the following in ruby 1.9
{ class: 'smthg', :'data-type' => 'a type' }
Note that you can still keep using the "old" hash syntax as well. It is a matter of preference. Personally for hashes with only symbols as keys, I use the clean/short version. I generally try not to mix hash-style in a single hash :)

Why can't I make a new hash from selected keys in ruby?

This has been bugging me for a while. It's not a difficult thing, but I don't know why there's no easy way to do it already, and I bet there is and I don't see it.
I just want to take a hash, like this:
cars = {:bob => 'Pontiac', :fred => 'Chrysler',
:lisa => 'Cadillac', :mary => 'Jaguar'}
and do something like
cars[:bob, :lisa]
and get
{:bob => 'Pontiac', :lisa => 'Cadillac'}
I did this, which works fine:
class Hash
def pick(*keys)
Hash[select { |k, v| keys.include?(k) }]
end
end
ruby-1.8.7-p249 :008 > cars.pick(:bob, :lisa)
=> {:bob=>"Pontiac", :lisa=>"Cadillac"}
There's obviously a zillion easy ways to do this, but I'm wondering if there's something built in I've missed, or a good an un-obvious reason it's not a standard and normal thing? Without it, I wind up using something like:
chosen_cars = {:bob => cars[:bob], :lisa => cars[:lisa]}
which isn't the end of the world, but it's not very pretty. It seems like this should be part of the regular vocabulary. What am I missing here?
(related questions, include this: Ruby Hash Whitelist Filter)
(this blog post has precisely the same result as me, but again, why isn't this built in? http://matthewbass.com/2008/06/26/picking-values-from-ruby-hashes/ )
update:
I'm using Rails, which has ActiveSupport::CoreExtensions::Hash::Slice, which works exactly as I want it to, so problem solved, but still... maybe someone else will find their answer here :)
Just to help others, some years after the fact:
Slice works nicely to do what I wanted.
> cars.slice(:bob, :lisa)
=> {:bob=>"Pontiac", :lisa=>"Cadillac"}
I've always thought that was a weird omission as well, but there really is no simple, standard method for that.
Your example above might be unnecessarily slow because it iterates over all the hash entries whether we need them or not, and then repeatedly searches through the keys parameter array. This code should be a bit faster (assuming that would ever matter -- and I haven't tried to benchmark it).
class Hash
def pick(*keys)
values = values_at(*keys)
Hash[keys.zip(values)]
end
end
select deserves at least to be mentioned:
cars = {:bob => 'Pontiac', :fred => 'Chrysler',
:lisa => 'Cadillac', :mary => 'Jaguar'}
people = [:bob, :lisa]
p cars.select{|k, _| people.include?(k)}
#=> {:bob=>"Pontiac", :lisa=>"Cadillac"}
Ruby makes it possible to add that feature without much pain:
class Hash
alias old_accessor :[]
def [](*key)
key.is_a?(Array) ? self.dup.delete_if{|k, v| !key.include? k} : old_accessor(key)
end
end
I hope this helps. I know it's not a built-in feature.
{ height: '178cm', weight: '181lbs', salary: '$2/hour' }.select { |k,v| [:height, :weight].include?(k) }

ruby keyword arguments of method

How can I declare a method with keyword arguments just like rails do. some examples may be
Person.find(:all, :conditions => "...").
How can I use symbols to create methods similar to the above?
I am very new to ruby. Thanks in advance!
Ruby doesn't actually have keyword arguments. Rails is exploiting a feature of Ruby which lets you omit the braces around a hash. For example, with find, what we're really calling is:
Person.find(:all, { :conditions => "...", :offset => 10, :limit => 10 } )
But if the hash is the last argument of the method, you can leave out the braces and it will still be treated as a hash:
Person.find(:all, :conditions => "...", :offset => 10, :limit => 10)
You can use this in your own methods:
def explode(options={})
defaults = { :message => "Kabloooie!", :timer => 10, :count => 1 }
options = defaults.merge(options)
options[:count].times do
sleep options[:timer]
puts options[:message]
end
end
And then call it:
explode :message => "Meh.", :count => 3
Or call it without an argument, resulting in all default values being used:
explode
Since Ruby 2.0, ruby does have keyword arguments.
def my_method(arg1, name: 'defaultName', number: 0)
puts arg1, name, number
end
I agree with accepted answer given by Samir Talwar and christopherwright. The only potential downside is that you get no warnings if you use an incorrect keyword symbol as an argument or when looking up an option, it just ends up ignored. If that's something you're concerned about, the gem hash_keyword_args addresses it. The idiom would be
def explode(opts={})
opts = opts.keyword_args(:message => "Kabloooie!", :timer => 10, :count => 1)
opts.count.times do
sleep opts.timer
puts opts.message
end
end
Notice the use of accessor methods so you'll get a NoMethodError if you mistype a keyword. And the calling behavior is:
explode(:message => "Okay") # works
explode(:msg => "Oops") # raises ArgumentError
The gem also provides a few other features you might or might not care about, such as being able to indicate that a keyword is required. I've been using it happily for a while now.
(Disclaimer: I'm the author of the gem.)
You just need to define a method where one of the parameters is a hash. It's actually pretty simple.
def method(arg1, params)
name = params[:name]
number = params[:number]
And then call it like:
method(arg1, :name => 'Eric', :number => 2)
Two notes:
In Ruby, you don't need to surround the parameters hash in {} when you call the method in most cases, unless you have something complicated going on like passing multiple hashes. In that case, make sure you surround those parameters with {}
Ruby is dynamically typed, so you don't need to say that params is a hash when you define the method.
Ruby 2.0 introduced real keyword arguments, and Ruby 2.1 added required keyword arguments.
There's a nice article up at https://chriszetter.com/blog/2012/11/02/keyword-arguments-in-ruby-2-dot-0/ on this, I've borrowed the examples from there:
Ruby 2.0+:
def exclaim(text, exclamation: '!', number: 7)
text + exclamation * number
end
exclaim('hello', number: 4) #=> 'hello!!!!'
# equivalent:
exclaim('hello', {:number => 4}) #=> 'hello!!!!'
Ruby 2.1+:
def exclaim(text, exclamation: '!', number:)
text + exclamation * number
end
exclaim('Yo', number: 5) # => 'Yo!!!!!'
exclaim('Yo') # raises: ArgumentError: missing keyword: number
Since Ruby is typed dynamically, just do :
def my_method(arg1, arg2)
#things
end
example:
my_method(:test, {:somehash => "yay"})
or
my_method :test, :somehash => "yay"
or
my_method(:test, :somehash => "yay")

Ruby => operator... eg: :text => /Log In/

What does this do? I find the example here, but other than what it does, what does it mean? I can't find anything on google because well, I am not sure what '=>' is even called in this context.
More examples here:
http://mechanize.rubyforge.org/mechanize/EXAMPLES_rdoc.html
In :text => /Log In/, you are passing a hash to page's link_with function, and the key in the hash is :text and its corresponding value is /Log In/.
Basically: :x => y means that :x is a key in a hash that maps to a value of y.
passing hashes to functions like this allows you to have something like (but not exactly) named parameters.
UPDATE:
A symbol of the form :something is called.... a symbol! You can think of them sort of like global string constants (but they're not quite the same). Now, when you think back to something like:
login_page.form_with(:action => '/account/login.php')
What you're actually doing is constructing a new hash on the fly. You create a new element in the hash, where the key is a string with the value "action", and the value of that element is "/account/login.php" (in this case, also a string, but I'm pretty sure you can store other things in hashes besides strings).
...whew! It's been a while since I've worked with Ruby. I hope I got that all correct. ;)
Some good looking pages here (more can be found by searching google for "ruby symbol")
http://glu.ttono.us/articles/2005/08/19/understanding-ruby-symbols
http://www.troubleshooters.com/codecorn/ruby/symbols.htm#_What_are_symbols
It associates a value with an index for hashes.
obj.method :text => /Log In/
is shorthand for
obj.method {:text => /Log In/}
It's used to create a hash expression, as in { key => value }.
Also, when used as the last parameter in a method call, the { } are not needed, so the key => value can appear alone.
>> p({:a => 1, :b => 2})
{:a=>1, :b=>2}
=> nil
>> p :c=>3, :d=>4
{:d=>4, :c=>3}
=> nil
>> t = { :e=>5, :f=>6 }
=> {:f=>6, :e=>5}
This shorthand is really nice in poetry mode, where a literal hash following a method name would look like a block.

Resources