0

Suppose I have two models that are similiar. One is called Primer3Template which holds a subset of the fields on Primer3Parameter.

I would like puts only the fields from Primer3Template which exist in Primer3Parameter, as well as upcase the field name and add some string interpolation. I have the code partially working, like this:

> t = Primer3Template.new
> @primer3_parameter = Primer3Parameter.where(:batch_detail_id => 7146)
> t.attributes.each  do | name, value |
>     puts "#{name.upcase}="
>   end

So far so good, this outputs:

ID=
TYPE=
USER_ID=
BATCH_DETAIL_ID=
GENERATED=
STATUS=
P3_FILE_TYPE=
....etc

Next I am trying to output the value of the field from the @primer3_parameter variable, which has the same name as the current name being processed by the loop. I have tried this:

> t.attributes.each  do | name, value |
>     puts "#{name.upcase}=#{@primer3_parameter.name}"
>   end

But this is outputting the name of the class, which is not what I want:

ID=Primer3Parameter
TYPE=Primer3Parameter
USER_ID=Primer3Parameter
BATCH_DETAIL_ID=Primer3Parameter
GENERATED=Primer3Parameter

I want it to skip some fields, and print the value of the field, something like this:

BATCH_DETAIL_ID=7146
GENERATED=true
STATUS=active
P3_FILE_TYPE=Type2

I also tried this:

>  t.attributes.each  do | name, value |
> x = "@primer3_parameters.first.#{name}"
> puts "#{name.upcase}=#{x}"
> end

Which gave me:

ID=@primer3_parameters.first.id
TYPE=@primer3_parameters.first.type
USER_ID=@primer3_parameters.first.user_id
BATCH_DETAIL_ID=@primer3_parameters.first.batch_detail_id
GENERATED=@primer3_parameters.first.generated

3 Answers 3

2

This:

@primer3_parameters = Primer3Parameter.where(:batch_detail_id => 7146)

returns a collection association. If you want to traverse the Primer3Parameter associated records you have to iterate through them. Like this:

@primer3_parameters.each do |primer3_parameter|
  primer3_parameter.attributes.each do |name, value|
  .....

and the rest is how you did it before.

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

2 Comments

Hi @ChuckE , thanks for your answer. I would like to traverse the t variable (Primer3Template) and use the name to retrieve the value of the same field on Primer3Parameter. I am thinking instance_variable_get will do it but I can't quite get the syntax right.
but your @primer3_parameter variable is not a Primer3Parameter instance, it is a collection of many.
1

dont use eval for this. You might get hurt!

Here is a good alternative

attribute_names = Primer3Template.accessible_attributes
@primer3_parameter = Primer3Parameter.where(:batch_detail_id => 7146)
attribute_names.each do |attr_name|
  puts "#{attr_name.upcase}=#{@primer3_parameter.read_attribute(attr_name)}"
end

Instead of @primer3_parameter.read_attribute(attr_name) I think you could do @primer3_parameter[attr_name] but I'm not sure if there are any drawbacks

Comments

0

Got it!!!

> t = Primer3Template.new
> p = Primer3Parameter.where(:batch_detail_id => 7146).first
> t.attributes.each do |name, value|
>     x = eval("p.#{name}")
>     puts "#{name.upcase}=#{x}"
>   end

Output

ID=15
TYPE=Primer3Parameter
USER_ID=
BATCH_DETAIL_ID=7146
GENERATED=false
STATUS=ready
P3_FILE_TYPE=settings
P3_FILE_ID=
P3_FILE_FLAG=false
P3_COMMENT=
SEQUENCE_EXCLUDED_REGION=
SEQUENCE_FORCE_LEFT_END=-1000000
SEQUENCE_FORCE_LEFT_START=-1000000

Did I mention I love Ruby? I hope this helps someone else.

EDIT - Improved Solution

  • Doesn't requiring instantiating the template class
  • Only returns the accessible fields which is exactly what I wanted

.

 Primer3Template.accessible_attributes.each do |name|
      x = eval("p.#{name}")
      puts "#{name.upcase}=#{x}"
 end

6 Comments

Maybe you can use x = p.send(name) to process a Dynmamic Dispatch instead of using eval
` Primer3Template.accessible_attributes.each do |name| x = p.send(name) puts "#{name.upcase}=#{x}" end` Object#send
The trick was not really an answer to your question, just a way to avoid eval function. My goal is reached if improvement is useful ;)
Do you want all the accessible attribute names from Primer3Template printed out, even when there isn't a corresponding accessible attribute in Primer3Parameter?
@Peter Alfvin yes that's exactly what I want. Primer3Parameter is a superset of Primer3Template (both models are mapped to the same physical table via STI)
|

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.