CamelCase instead of snake_case in Rails DB

2019-03-29 10:41发布

问题:

My DB tables and field names are in CamelCase. Is it possible to convert those names into snake_case on a fly? To make model methods look pretty?

The app is JRubyOnRails 3.0 / MSSQL DB / ActiveRecord-JDBC-adapter.

回答1:

@arkadiy,as a matter of fact, I was looking into this just this very day.

For table names, we of course have the set_table_name method:

class CamelCasedFoo < ActiveRecord::Base
  set_table_name :CamelCasedTable
end

For things like primary keys, we have set_primary_key:

class CamelCasedBar < ActiveRecord::Base
  ...
  set_primary_key "CamelCasedTableID"
end

And it should be possible to alias funky, legacy column names to something more rails-friendly with alias_attribute:

class CamelCasedBaz < ActiveRecord::Base
  ...
  alias_attribute :preferred_delivery, :DeliveryFrequency
end

One key thing to keep in mind is to watch out for any column names that are ruby or rails keywords or magic field names.

Rails appears to have all that metaprogramming goodness to allow you to work around legacy db table names and columns. You may wish to have a read of Jonathan Hui's blog post on "Ruby on Rails 3 Model Working with Legacy Database". And you might want to have a look at the safe_attributes gem.



回答2:

I had the same need. @buruzaemon's answer of setting the table_name and primary_key are good but I have a few suggestions to make it better.

I believe the set_* style methods have fallen out of favor and simply setting the attribute directly is recommended these days. So

class Project < ActiveRecord::Base
  self.table_name = 'Projects'
  self.primary_key = 'ProjectId'
end

In addition using alias_attribute to manually alias every attribute seems tedious. It also seems like it could be easy to forget one. Although @Behrangf recommends against it, I don't see anything wrong with using a little meta-programming magic to automatically provide the snake_case version of your attributes. I've created a module that does this automatically. It's not even tied to ActiveRecord so you could also use it in an API wrapper or something else that is mirroring a system that doesn't follow the Ruby conventions. I am tracking the module on Gist but for convenience is is reproduced below:

module Snakeable

  # Patch in our automatic snake_case methods
  def method_missing method, *args 
    if is_snake_case?(method) &&
      respond_to?(camelized = method.to_s.camelize.to_sym)
      send camelized, *args
    else
      super
    end
  end

  # So the object including this module will respond to
  # Object#respond_to? correctly
  def respond_to? method, *args
    super || (
      is_snake_case?(method) &&
      super(method.to_s.camelize.to_sym, *args)
    )
  end

  private

  # Is the given method using the snake_case format
  def is_snake_case? method
    method.to_s =~ /^[a-z]+(?:_[a-z]+)*[?=!]?$/
  end

end

This module does depend on ActiveSupport's camelize method.



回答3:

Yuck! You have my sympathy. I like old_school.names all the time, even when the engine allows for other malarkey...

I assume this is a legacy app?

How about creating a set of views for your rails app to work with?



回答4:

Ruby on Rails is opinionated software. It means that its designers have chosen to do things in a specific way and in order to be able to use RoR with success, pleasure, ease, smoothness, etc. you must do it in that specific way. As such if you can't or don't want to follow RoR's table and column naming conventions you are advised to select another framework.

However if you want to stay with RoR yet you want snake_case method names, you can open the ActiveRecord::Base class, intercept calls to undefined methods, ensure that they match the ^[a-z]+(_[a-z]+)*$ regular exception, and if so, convert them to the upper case and call the upper case method. BUT I STRONGLY ADVISE YOU NOT TO DO THAT!!!* :D