Is there a one-line way to use include if the array it's searching may not be assigned?
I've tried a lot of variants of
(foo || []).include?(:bar)
but without success
If foo really is nil, as opposed to undefined, then (foo || []).include?(:bar) will do what you want, however if foo is not set to anything yet, then you will get a NameError so we can check for that with a longer oneliner...
defined?(foo) ? (foo || []).include?(:bar) : false
(foo ||= []).include?(:bar)
That will do the trick.
Maybe this?
foo.includes? :bar if foo
Since you are using partials, put this on the top of your partial:
<% foo = [] unless local_assigns.has_key?(:foo) # for Arrays %>
<% foo = {} unless local_assigns.has_key?(:foo) # for Hashes %>
<% foo = "" unless local_assigns.has_key?(:foo) # for Strings %>
etc.
This is the proper way of checking if a variable used in a partial has been set at all.
In the views using the foo partial:
<% render :partial => "foo", :locals {:a => 1, :foo => [2, 3, 4]} %>
<% render :partial => "foo", :locals {:a => 1} %>
In the first case, the foo variable will be [2,3,4] in the foo partial.
In the second case, the foo variable will not be put in local_assigns and will thus be given a default value as per the code above.
Related
Simple question. I am using Ruby V1.9.3 and I type;
<%= f_array = ['a','b','c'] %><br>
<%= f_array.join(' , ') %><br>
but they show up on the browser as;
["a", "b", "c"]
a,b,c
As far as I remember (until Ruby V1.8.3), it used to show up like;
abc
a,b,c
Did Ruby change their specification or did I miss something??
You error is here
<%= f_array = ['a','b','c'] %>
The statement <%= represents a print statement. Change it to
<% f_array = ['a','b','c'] %>
and the line will not be printed. ["a", "b", "c"] is the result of the inspection of an array.
2.1.5 :003 > puts ['a','b','c'].inspect
["a", "b", "c"]
For what it is worth, the code has another issue. Your view should not contain assignments. That's part of the business logic of your application.
Is there a better way to write this? basically I want to add an argument to a hash. if the argument is a key-val pair, then id like to add it as is. if the argument is a string i'd like to add it as a key with a nil value. the below code works, but is there a more appropriate (simple) way?
2nd question, does calling an each method on an array with two arguments |key, val| automatically convert an array to a hash as it appears to?
#some_hash = {}
def some_method(input)
if input.is_a? Hash
input.each {|key, val| #some_hash[key] = val}
else
input.split(" ").each {|key, val| #some_hash[key] = val}
end
end
some_method("key" => "val")
This gives the result as instructed in the question, but it works differently from the code OP gave (which means that the OP's code does not work as it says):
#some_hash = {}
def some_method(input)
case input
when Hash then #some_hash.merge!(input)
when String then #some_hash[input] = nil
end
end
some_method("foo" => "bar")
some_method("baz")
#some_hash # => {"foo" => "bar", "baz" => nil}
Second question
An array is never automatically converted to a hash. What you are probably mentioning is the fact that the elements of an array within an array [[:foo, :bar]] can be referred to separately in:
[[:foo, :bar]].each{|f, b| puts f; puts b}
# => foo
# => bar
That is due to destructive assignment. When necessary, Ruby takes out the elements of an array as separate things and tries to adjust the number of variables. It is the same as:
f, b = [:foo, :bar]
f # => :foo
b # => :bar
Here, you don't get f # => [:foo, :bar] and b # => nil.
I have some code in a view script that iterates through an array of arrays:
<% #rows.each do |data| %>
<%= data[0] %>: <%= data[1] %><br>
<% end %>
How can I easily convert each data array to a hash so that I can refer to each item with a key?
<%= data[:name] %>: <%= data[:email] %><br>
You can refer to the arrays with named values like this:
<% #rows.each do |name,email| %>
<%= name %>: <%= email %><br />
<% end %>
This assumes that every member of the #rows array will be the expected two-value array.
#Zach's answer is ok, but answering strictly what you asked for, it can be done this way:
#rows2 = #rows.map { |row| Hash[[:name, :email].zip(row)] }
#Zach and #tokland have supplied two fine answers. Sometimes it's nice to make first class data objects instead of relying on composition of primitive Hashes and Arrays. Struct is handy for this:
irb> EmailTuple = Struct.new :name, :email
=> EmailTuple
irb> rows = [%w{foo foo#example.com}, %w{bar bar#example.com}]
=> [["foo", "foo#example.com"], ["bar", "bar#example.com"]]
irb> rows2 = rows.map{ |row| EmailTuple[ *row ] }
=> [#<struct EmailTuple name="foo", email="foo#example.com">, #<struct EmailTuple name="bar", email="bar#example.com">]
irb> rows2.map{ |tuple| "#{tuple.name} has email #{tuple.email}" }
=> ["foo has email foo#example.com", "bar has email bar#example.com"]
Please consider this example:
- user_links_params = _user_link_params(current_user)
%a{ :'data-msgstore-path' => user_links_params[:'data-msgstore-path'],
:'data-user_id' => user_links_params[:'data-user_id'],
:class => user_links_params[:class],
}
/ too many html tags and stuff to fit in a simple link_to
I would be nice to fit all this in a simple statement like the following:
%a[_user_link_params(current_user)]
/ too many html tags and stuff to fit in a simple link_to
Yes, it's possible, and you were close:
%a{_user_link_params(current_user)}
From the HAML reference:
For example, if you defined
def hash1
{:bread => 'white', :filling => 'peanut butter and jelly'}
end
def hash2
{:bread => 'whole wheat'}
end
then %sandwich{hash1, hash2, :delicious => true}/ would compile to:
<sandwich bread='whole wheat' delicious='true' filling='peanut butter and jelly' />
I'd like to create a partial as follow:
%nav.tab_nav
%ul
%li.active
%a
Variable1
%li
%a
Variable2
%li
%a
Variable...n
Where variable1 variable2 etc exist, but the number of variables change, so I could traverse an array of arguments or something, but I don't know how to pass this array to the partial. Is there a way to pass a block or similar ?
Passing locals for partial:
= render :partial => "tabs", :locals => { :items => ["foo", "bar", "baz"] }
Looping part:
%nav
%ul
- items.each do |item|
%li
%a= item
http://guides.rubyonrails.org/layouts_and_rendering.html#passing-local-variables