开发者

Rails refactoring: Where would you put hash which maps one table's fields to another

开发者 https://www.devze.com 2023-02-02 21:49 出处:网络
So, I have a database of people on an external system, and I want to set up the code to easily create people records internal to our sysem based on the external system.The field names, of course, are

So, I have a database of people on an external system, and I want to set up the code to easily create people records internal to our sysem based on the external system. The field names, of course, are not the same, so I've written some code which maps from one table to the next.

class PeopleController < ApplicationController
...
  def new
    @person = Person.new
    if params[:external_id] then
       initialize_from_external_database params[:external_id]
    end
  end

  private
  def initialize_form_external_database(external_id)
    external = External::Person.find(external_id)
    if external.nil?
       ...
    else
       @person.name_last = exteral.last_name
       @person.name_first = external.first_name
       #...
       @person.valid?
    end
  end

end

Okay, so the stuff in the "else" statement I can write as a loop, which would use a hash something like:

FieldMappings = {
  :name_last => :last_name,
  :name_first => :first_name,
  :calculated_field => lambda {|external_person| ... },
  ...
}

But where would you put this hash? Is it natural to put it in the External::Person class because the only reason we access those records is to do this initialization? Or would i开发者_开发知识库t go in the controller? Or a helper?

Added: Using Rails 2.3.5.


I'd put this code in the External::Person to avoid Person even having to know it exists. Use a 'to_person' method (or maybe 'to_internal_person') on External::Person. Keep the Hash in External::Person and use it to perform the generation. Either way as JacobM says, you want this code in your model, not controller.

class PeopleController < ApplicationController
  def new
    if external = External::Person.find_by_id params[:external_id]
      @person = external.to_person
    else
      @person = Person.new
    end
  end
end


If you're in Rails 3.x (maybe also in 2.x, I'm not sure), you can put miscellaneous classes and modules in your /extras folder which is included in the autoloader path. This is where I always put things of this nature, but I' not aware of any Rails convention for this sort of thing.


First of all, I would do that work in your (internal) Person model -- give it a class method like create_person_from_external_person that takes the external person and does the assignments.

Given that, I think it would be OK to include the hash within that Person model, or somewhere else, as Josh suggests. What would be particularly cool would be to write a generic create_person_from_external_person method that would ask the external person for a hash and then do the mapping based on that hash; that approach could support more than one type of external person. But that may be overkill if you know this is the only type you have to deal with.

I wouldn't put it in the controller, but, again, I wouldn't do that work in the controller either.


You can put it on a module on the lib directory so you don't mess any of your classes that will be full of awesome code that will probably last many years. Another good reason is you can then include/require your mapping module everywhere you need it (maybe in your tests).

module UserMapping
  FIELDS = { :last_name => :name_last, .... }
end

If you drop the module on the lib and you use rails 3 you should put this on your config/application.rb file:

config.autoload_paths += %W(#{config.root}/lib)

On Rails::VERSION::MAJOR < 3 the lib directory is automatically added to the autoload_path

0

精彩评论

暂无评论...
验证码 换一张
取 消