Jared Knipp
Jared Knipp

Reputation: 5950

Rails 3 - Easily work with Pascal Case column names

We are beginning a Rails 3 front end to a newly developed application written in Java w/ SQL Server data layer.

Due to the team's previous experience, all column names are in Pascal Case (Id, Name, MyTableId) and table names are in singular form (not pluralized). Is there a way to easily globally overwrite the default rails conventions to work with this data model?

I realize this can be done by using set_table_name and column aliasing, but that kind of defeats the purpose of using Rails to quickly develop the application as we would have to duplicate our existing domain layer codebase.

I've found the code snippet below that will somewhat satisfy my needs, is this the best way / is this still valid?

http://snippets.dzone.com/posts/show/2034

Upvotes: 1

Views: 713

Answers (2)

Jared Knipp
Jared Knipp

Reputation: 5950

I here is what I came up with help from wilsona. Per answer, added

ActiveRecord::Base.pluralize_table_names = false  

to environment.rb.

I added this class in my models directory, and have all my models inherit from it.

class PascalCaseActiveRecord < ActiveRecord::Base
  self.abstract_class = true

  # all columns are uppercase
  set_primary_key 'Id'

  def self.reloadable?
    false
  end



  # convert to camel case attribute if in existence
  # record.name => record.Name
  # record.id => record.Id
  def method_missing(method_id, *args, &block)
    method_id = method_id.to_s.camelize if @attributes.include? method_id.to_s.camelize.gsub(/=/, '')
    super(method_id, *args, &block)
  end

#  def self.method_missing(method_id, *args)
#    # if its a finder method
#    if method_id.to_s.match(/^find_by_/)
#      puts "Before camelize #{method_id}"
#      s2 = method_id.to_s.sub("find_by_","").split('_and_')
#      s2.collect! {|s| s.camelize}
#      method_id = "find_by_" + s2.join("_and_")
#      puts "After camelize #{method_id}"
#    end
#    
#    super(method_id, *args)
#  end
#  
    # strip leading and trailing spaces from attribute string values
  def read_attribute(attr_name)
    value = super(attr_name)
    value.is_a?(String) ? value.strip : value
  end

  class << self # Class methods

    private
      # allow for find_by and such to work with uppercase attributes
      # find_by_name => find_by_Name
      # find_by_dob_and_height => find_by_Dob_and_Height
      def extract_attribute_names_from_match(match)
        match.captures.last.split('_and_').map { |name| name.camelize }
      end
  end
end

Upvotes: 0

A. Wilson
A. Wilson

Reputation: 8840

One part of your problem is solved by an option on ActiveRecord::Base. In your environments.rb, put

ActiveRecord::Base.pluralize_table_names = false

Your other problems, as far as I can tell, will have to be solved by diving into the model generator code and finding where it massages your attributes into its column names. Once the database and its schema follow your convention, ActiveRecord should (from my understanding) automatically generate its attributes with that convention. The easy way to test this is to create a quick record with your conventions, create a model on that record, and then use rails/console to print the result of column_names on an instance of that model.

EDIT: From your edit above, I can see that ActiveRecord's method_missing probably enforces case. Using that link should solve that issue, though.

Do beware, of course, that using Pascal case may cause some headaches with Ruby, since capitalized items without a scope resolution operator are taken to be Constants, not Objects. For example:

class Foo
  attr_reader :low,:Cap


  def initialize
     @low = "lowtest"
     @Cap = "Captest"
  end

  def bar
     self.low   #<==works
     self.Cap   #<==works
  end

  def baz
     low        #<==works
     Cap        #<==raises NameError
  end
end

This will just mean your model code will need to properly use self, which you should be doing anyway.

Upvotes: 2

Related Questions