netricate
netricate

Reputation: 1728

Iterating on database records to create attribute hash

Ruby Newbie here. First off, this is more philosophical than practical, so if there is a better way to accomplish this, please tell.

I have a table that looks roughly like:

╔════╦════════╦════════╦══════════╗
║ ID ║ label  ║ value  ║ thing_id ║
╠════╬════════╬════════╬══════════╣
║  1 ║ color  ║ red    ║        1 ║
║  2 ║ size   ║ medium ║        1 ║
║  3 ║ weight ║ heavy  ║        1 ║
╚════╩════════╩════════╩══════════╝

i query this and get a recordset for a particular thing.

thing_attributes = ThingAttributes.where(:thing_id => 1)

which results in a recordset of 5 or so rows from that table. I'd like to be able to create a has that allows me to create the equivalent of {"color" => "red", "size" => "medium", "weight" => "heavy" }. Thoughts?

Upvotes: 0

Views: 411

Answers (3)

Niels B.
Niels B.

Reputation: 6310

Okay, basically you are trying to imitate a schemaless database, because you want your different records to have different attributes. As long as you only have one custom attribute pr. record, this could work, but if your records have more attributes in difference than common, then you might want to consider having multiple models, look into the hstore datatype or look into a document database such as MongoDB.

Update

Reading your question again, I think I have a better solution, so I have deleted the original one.

I'm going to call your ThingAttributes class what I think it is - a CustomAttribute class. Because each record represents one custom attribute. A Thing can have many (in your example five) custom attributes.

So you can do this:

class CustomAttribute < ActiveRecord::Base
  belongs_to :thing
  attr_accessible :name, :value
end

class Thing < ActiveRecord::Base
  has_many :custom_attributes
end

Now you can find a thing, by writing

my_thing = Thing.find(3)

You can then find it's custom_attributes, by writing

my_thing.custom_attributes

This will return an array of custom attributes. However, you are (for some reason) asking for a hash. This can be done too. In your Thing class, define this method:

def custom_attributes_hash
  custom_hash = {}
  self.custom_attributes.each do |attr|
    custom_hash[attr.name] = attr.value
  end
  custom_hash
end

Now, you may want to be able to set attributes in a convenient way as well. Define this on your Thing class.

def set_custom_attribute(name, value)
  return unless name.present? # Short circuits method if an empty string or nil is being used as name.
  custom_attribute = self.custom_attributes.find_by_name(name) # Attemps to find custom attribute with the name
  if custom_attribute.nil? # Executes block if no attribute was found
    return unless value.present? # Short circuits method if nil or empty string was passed as value
    self.custom_attributes.create(name: name, value: value) # Creates and saves new custom attribute
  else
    if value.present? # Updates existing attribute if passed is not an empty string or nil.
      custom_attribute.update_attribute(:value, value)
    else
      custom_attribute.destroy # Deletes custom attribute from DB if set_custom_attribute was called with a nil or empty value.
    end
  end
end

Upvotes: 2

sunny1304
sunny1304

Reputation: 1694

I think this is what you are asking for :

Thing_model.rb

thing = Thing.find(1)

 def #{self.label}
    return self.value

Upvotes: 0

edymerchk
edymerchk

Reputation: 1263

I'm no sure if i'm getting well, but try this:

my_thing = Thing.find(1)
my_thing.color

Upvotes: 0

Related Questions