【问题标题】:Map from one object to another in Ruby在 Ruby 中从一个对象映射到另一个对象
【发布时间】:2016-03-14 07:19:11
【问题描述】:

我有两个对象,一个 UserData 对象和一个 User 对象。目前它们看起来像这样:

user_data.rb

class UserData < ActiveRecord::Base
  self.table = "users"
end

user.rb

class User
  attr_accessor :first_name, :last_name, :email, :password
end

我现在要做的是将 UserData 对象映射到 User 对象,反之亦然。对于第一种情况,我有以下代码:

module Mappers
  module UserMapper
   def map user
     @user = UserData.new
     @user.first_name = user.first_name
     @user.last_name = user.last_name
     @user.password = user.password
     @user.email = user.email
   end
  end
end

但是,问题是每当我向用户表添加新列时,我也必须在映射器中添加代码。当我的代码中有大量需要映射的对象时,它会变得非常混乱。我的问题是:有没有更好的/动态的方法来做到这一点?理想的情况是我不必再接触 Mapper 代码。

【问题讨论】:

  • 你为什么不从ActiveRecord::Base 继承你的User 类。为什么要保留两个单独的类并映射属性?
  • 我想隔离我的数据模型,并且不知道我的应用程序中除了数据模型本身之外的任何地方都存在 Active Record。
  • 数据应该和模型一起保存。这就是它们存在的原因。如果您想保持逻辑隔离,我建议在您的应用程序中使用服务层。但将数据保留在它实际所属的位置。作为参考,您可以阅读this article

标签: ruby-on-rails ruby


【解决方案1】:

您可以通过调用attribute_names 类方法从 ActiveRecord 模型中获取属性名称列表。有了这些,就很容易遍历它们并依次获取和分配每个属性:

module UserMapper
  def map(user)
    @user = UserData.new do |user_data|
      UserData.attribute_names.each do |attr_name|
        next unless user.respond_to?(attr_name)
        user_data[attr_name] = user.public_send(attr_name)
      end
    end
  end
end

如果需要,您可以使用相同的方法在 User 类中动态创建 attr_accessors:

class User
  attr_accessor *UserData.attribute_names
end

【讨论】:

    【解决方案2】:

    你可以使用一点 ruby​​ 元编程来完成这个:

    class User
      ATTRS = [:first_name, :last_name, :email, :password]
      attr_accessor *ATTRS
    end
    
    module Mappers
      module UserMapper
       def map(user)
         @user = UserData.new
         User::ATTRS.each do |attr|
           @user.send("#{attr}=", user.send(attr))
         end
       end
      end
    end
    

    然后你只需修改ATTRS,一切都会自动运行!

    【讨论】:

      【解决方案3】:

      你可以根据这个问题做点什么:Fastest/One-liner way to list attr_accessors in Ruby?

      module Mappers
        module UserMapper
          def map user
            @user = UserData.new
            user.attributes.inspect.each do |attr|
              @user.public_send("#{attr}=", user.public_send(attr))
            end
          end
        end
      end
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2018-02-10
        • 1970-01-01
        • 1970-01-01
        • 2017-01-26
        • 1970-01-01
        • 1970-01-01
        • 2019-04-27
        相关资源
        最近更新 更多