0

I have 3 classes: Invoice, Address and Customer (but for this problem, only the Invoice and Address class are relevant)

This is my Invoice class:

class Invoice attr_reader :billing_address, :shipping_address, :order def initialize(attributes = {}) @billing_address = attributes.values_at(:billing_address) @shipping_address = attributes.values_at(:shipping_address) @order = attributes.values_at(:order) end end 

and this is my Address class:

class Address attr_reader :zipcode, :full_address def initialize(zipcode:) @zipcode = zipcode url = 'https://viacep.com.br/ws/' + zipcode.to_s + '/json/' uri = URI(url) status = Net::HTTP.get_response(uri) if (status.code == "200") response = Net::HTTP.get(uri) full_address = JSON.parse(response) @full_address = full_address else p "Houve um erro. API indisponível. Favor tentar novamente mais tarde." @full_adress = nil end end end 

And this is my Customer class (not much relevant, but i'm showing for better explanation of the problem)

class Customer attr_reader :name, :age, :email, :gender def initialize(attributes = {}) @name = attributes.values_at(:name) @age = attributes.values_at(:age) @email = attributes.values_at(:email) @gender = attributes.values_at(:gender) end end 

As you can see, my Invoice class has 3 instance variables and my Address class has 2 instance variables.

So, if i test something like that:

cliente = Customer.new(name: "Lucas", age: 28, email: "[email protected]", gender: "masculino") endereco = Address.new(zipcode: 41701035) entrega = Invoice.new(billing_address: endereco, shipping_address: endereco) p endereco.instance_variables 

[:@zipcode, :@full_address]

p entrega.shipping_address.instance_variables 

[]

My instance variables can be acessed through the variable "endereco", that is an Address object, but can't be acessed through entrega.shipping_address that is also an Address object.

To be more precise, if a try this:

p entrega.shipping_address 

I get this return:

[#<Address:0x00000001323d58 @zipcode=41701035, @full_address={"cep"=>"41701-035", "logradouro"=>"Rua Parati", "complemento"=>"", "bairro"=>"Alphaville I", "localidade"=>"Salvador", "uf"=>"BA", "unidade"=>"", "ibge"=>"2927408", "gia"=>""}>] 

My full object are being returned, but i can't access the content of my @full_address instance variable.

If a do this:

p entrega.shipping_address.full_address 

I get a NoMethodError:

solucao.rb:8:in `<main>': undefined method `full_address' for #<Array:0x000000012d25e8> (NoMethodError) 

I'm trying to understand why i can't access the content inside my object if i have the full object. Maybe i'm trying to access in the wrong way, i don't know.

Can someone help ?

2 Answers 2

3

values_at returns an array of values (see https://apidock.com/ruby/Hash/values_at for explanation)

Change

@shipping_address = attributes.values_at(:shipping_address) 

into

@shipping_address = attributes[:shipping_address] 

And that way @shipping_address will contain an Address object, not an array that contains an Address object

Sign up to request clarification or add additional context in comments.

3 Comments

This worked too !! thank you very much for your help
Another thing that worked was that: p entrega.shipping_address[0].full_address["logradouro"] If I use an indexer, i can acess the object Address inside the array. I didn't noticed that i had an structure of an object inside an array.
Yes you could access the first element of the array with [0] or even first but unless your design calls for multiple shipping addresses in the entrega you shouldn't make it an array.
3

If you take a look at the error, it says

undefined method `full_address' for #<Array:0x000000012d25e8> 

You're trying to call full_address on an array. So this means that entrega.shipping_address returns you an array (which it does, of course, take a closer look at the output).

If I were you, I'd look into how shipping_address is implemented. It's a simple attr_reader, so it's backed by an instance variable. Must be you initialize that instance variable to a wrong value (it gets an array instead of an address). Look closely at that initialization code and try to run it in IRB session. You should see the problem.

2 Comments

oh man... thanks for the advice... i was blind. I just changed my implementation of the Invoice Class to this: class Invoice attr_reader :billing_address, :shipping_address def initialize(billing_address:, shipping_address:) @billing_address = billing_address @shipping_address = shipping_address end end And it worked. But now i have another problem... i had to remove the "order" parameter from the constructor, because i was getting an error of missing argument. Is there someway to make the constructor accept this argument if it's null ?
@LucasBarreto: not sure what you mean, but you can set default values to parameters: def initialize(billing_address:, order: nil) Here billing_address is a required parameter and order is optional

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.