0

ruby 2.1.1

Is there a way to do the logic in this piece of code in one line or a more concise manner?

user = User.new
h = Hash.new
attrs = [:name, :foo, :bar]
attrs.each do |a|
    h[a] = user[a] if user.has_attribute? a
end
return h
5
  • From a matter of style, Hash.new with no options is almost always written as simply { }. It's also unnecessary to use return r when r at the end of the method has exactly the same effect. The only place return is normally used is to break out of a method early. Commented May 31, 2014 at 22:51
  • Are you using Rails ? Commented May 31, 2014 at 23:05
  • @ArupRakshit yes, I am using Rails 4.1.1 Commented May 31, 2014 at 23:10
  • tag your question also then... Commented May 31, 2014 at 23:10
  • @ArupRakshit k, tagged, at first I thought ruby would have a complete solution to this issue. Didn't think rails would have such a better alternative. Now I know, thanks! Commented May 31, 2014 at 23:14

3 Answers 3

3

If you're using Rails and User is an ActiveRecord model (which it looks like given your use of has_attribute?) then this will do the same thing:

user = User.new
...
return user.attributes.slice("name", "foo", "bar")

Or, if you really want symbols:

return user.attributes.with_indifferent_access.slice(:name, :foo, :bar)
Sign up to request clarification or add additional context in comments.

3 Comments

Your answer is compact one liner.. But just remove return, It is not need.
I left the return there to make it clear to the asker that this is the final result, in place of what he was returning before. Nothing wrong with a return if it adds clarity. :)
I concede… I just like my returns :)
1

It seems you are on Rails. If so,then -

attrs = [:name, :foo, :bar]
# the result hash will be returned, if last line of the method.
user.attributes.extract!(*attrs) 

Look these methods extract! and attributes.

Example :

arup@linux-wzza:~/Rails/app> rails c
Loading development environment (Rails 4.1.1)
2.0.0-p451 :001 > h = { a: 1, b: 2, c: 3, d: 4 }
 => {:a=>1, :b=>2, :c=>3, :d=>4}
2.0.0-p451 :002 > h.extract!(:a ,:b ,:x)
 => {:a=>1, :b=>2}
2.0.0-p451 :003 >

Comments

0

Answers above are correct in Rails scope, I'l just add generic solution:

# assuming user[a] returns nil, if user have no a attribute
[:name, :foo, :bar].
  map{|a| [attr, user[a]]}.
  reject{|k, v| v.nil?}.
  to_h

# assuming user[a] can raise if not user.has_attribute?(a)
[:name, :foo, :bar].
   map{|a| [attr, user.has_attribute?(a) && user[a]]}.
   reject{|k, v| !v}.
   to_h

I've formatted them as NOT one-liners, but they are still one-statements :)

Basically, the trick is "invent the right method chain to convert one sequence to other", and requires to know all Enumerable sequence-transforming methods (map/select/reduce/reject/...), as well as a method to transform array of key-value pairs into hash (#to_h is standard in Ruby 2.1.1)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.