richard
richard

Reputation: 1585

Dynamically determining Rails model attributes

I have a model (simplified version below - the full one has a lot more fields) on which I want to do a search.

class Media < ActiveRecord::Base

  attr_accessible :subject, :title, :ref_code

  validates :title, :presence => true
  validates :subject, :presence => true

  def self.search(terms_hash)
    return if terms_hash.blank?

    composed_scope = self.scoped

    terms_hash.each_pair do |key, value|
    if self.respond_to? key and not value.is_blank?
      value.split(' ').each do |term|
        term = "%#{term}%"
        composed_scope = composed_scope.where("#{key} LIKE ?", term)
      end
    end
    composed_scope
  end
end

Since the advanced search form is almost identical to the form used to create/update instances of the model, I want to create a method that dynamically looks through the params list of the request and matches form fields to model attributes via the name. So if the search request was,

/search?utf8=✓&ref_code=111&title=test&subject=code&commit=Search

then my controller could just call Media.search(params) and it would return a scope that would search the appropriate fields for the appropriate value(s). As you can see I tried using respond_to? but that is only defined for instances of the model rather than the actual model class and I need something that ignores any params not related to the model (eg. utf8 and commit in this case). If this all works well, I plan to refactor the code so that I can reuse the same method for multiple models.

Is there a class method similar to respond_to?? How would you go about the same task?

I know this is related to get model attribute dynamically in rails 3 but it doesn't really answer what I'm trying to do because I want to do it on the the model rather than an instance of the model.

Upvotes: 1

Views: 731

Answers (1)

mu is too short
mu is too short

Reputation: 434935

There is a columns method on ActiveRecord model classes so you can easily get a list of attribute names:

names = Model.columns.map(&:name)

You could remove a few common ones easily enough:

names = Model.columns.map(&:name) - %w[id created_at updated_at]

The accessible_attributes class method might also be of interest, that will tell you what has been given to attr_accessible.

Upvotes: 5

Related Questions