SupremeA
SupremeA

Reputation: 1621

Getting a value from an array of hashes in Ruby

I have an array:

address => [{"data"=>{"zip"=>"60628", "state"=>"IL", "city"=>"chicago", "street"=>"123 Main St. Apt 2"}, "primary"=>true}]

I want to show each piece in the right format on my view like:

123 Main St. Apt 2
Chicago, IL 60628

I am having trouble getting the logic correct to show this.

Where should this logic go, as a method in my model or in the actual view?

I tried:

<% @applicant.address.map{|x| x[:data]}.each do |address| %>
  <%= address.street %><br><%= address.city %>, <%= address.state %> <%= address.zip %> <br>
      <% end %>

but got:

=> [{"zip"=>"60628", "state"=>"IL", "city"=>"chicago", "street"=>"123 main st Apt 2"}]

Upvotes: 1

Views: 94

Answers (2)

peter
peter

Reputation: 42207

The map gives you a new array and if you use hashes you need to access the values with the hash[:key] or hash["key"] operator, try this:

<% @applicant.address.each do |address_hash| %>
  <% address = address_hash["data"] %>
  <%= address["street"] %><br><%= address["city"] %>, <%= address["state"] %> <%= address["zip"] %> <br>
<% end %>

But if I were you , I'd put the data in an array of structs, it's more readable.

In your model or helper:

address = Struct.new(:street, :city, :state, :zip)
address.street = ..
...
@addresses << address
etc

In your view:

<% @addresses.each do |address| %>
  <%= address.street %><br><%= address.city %>, <%= address.state %> <%= address.zip %> <br>
<% end %>

Upvotes: 2

Mario Carrion
Mario Carrion

Reputation: 672

For your first question something like this should suffice:

#!/usr/bin/env ruby

require 'ostruct'

address = [
  {
    'data'    => { 
                   'zip'    => '60628',
                   'state'  => 'IL',
                   'city'   => 'chicago',
                   'street' =>'123 Main St. Apt 2'
                 },
    'primary' => true
   }
]

class AddressPresenter
  def initialize(address)
     @address = OpenStruct.new(address)
  end

  def to_s
    "#{@address.street} \n#{@address.city} #{@address.state} #{@address.zip}"
  end
end

address.each do |a|
  puts AddressPresenter.new(a['data'])
end

Now, for the second question, I would implement a Presenter class whose only goal is to "present" the data in whatever format you need in the view, this allows you to keep your views with 0 presentation logic. So in this case the class AddressPresenter could be reworked to return in the to_s the right HTML you need in your view. And you would do something like:

<% @applicant.address.each do |address| %>
  <%= AddressPresenter.new(address['data']).to_s %>
<% end %>

By having a separated presenter class, you get the following benefits:

  1. Your models don't worry about how to present/render stuff because that's not their job
  2. You can test this presenter to confirm it returns whatever you're expecting in the view
  3. Your views don't contain any complicated logic

Upvotes: 1

Related Questions