【问题标题】:How can I make DRY repeated code used in model methods and in controllers in Rails 3?如何在 Rails 3 的模型方法和控制器中使用 DRY 重复代码?
【发布时间】:2011-05-02 04:06:09
【问题描述】:

我有以下方法 对于单个模型,并且可能有更多。我也可能在助手中有一些重复的代码。我怎样才能让它变干?

25   def full_name
 26     client = LinkedIn::Client.new(ENV['LINKEDIN_KEY'], ENV['LINKEDIN_SECRET'])
 27     client.authorize_from_access(self.atoken, self.asecret)
 28     client.profile(id => self.uid)
 29     client.profile.first_name + " " + client.profile.last_name
 30   end
 31 
 32   def image_url
 33     client = LinkedIn::Client.new(ENV['LINKEDIN_KEY'], ENV['LINKEDIN_SECRET'])
 34     client.authorize_from_access(self.atoken, self.asecret)
 35     client.profile(id => self.uid)
 36     client.profile(:fields => "picture-url").picture_url
 37   end

每次我需要对 API 进行方法调用时,我都会重复大部分情况下实例化客户端和访问配置文件 ID 的代码。只是 API 发生了变化。

当我还需要调用(不同型号的)控制器时会发生什么?

29     if @review.save
 30       flash[:notice] = "Successfully created review."
 31       # check if allowed to post to LinkedIn and post
 32       if @review.post_linkedin?
 33         client = LinkedIn::Client.new(ENV['LINKEDIN_KEY'], ENV['LINKEDIN_SECRET'])
 34         client.authorize_from_access(current_user.atoken, current_user.asecret)
 35         debugger 
 36         client.update_network("has shared expertise on <a")
 37       end

我怎样才能让它更干?

【问题讨论】:

    标签: ruby-on-rails model dry linkedin


    【解决方案1】:

    我同意@thekindofme,但我会添加一些缓存,因此您不必每次都调用 LinkedIn API:

    def linkedin_profile
      @linkedin_profile ||= set_linkedin_profile
    end
    
    def set_linkedin_profile
      client = LinkedIn::Client.new(ENV['LINKEDIN_KEY'], ENV['LINKEDIN_SECRET'])
      client.authorize_from_access(self.atoken, self.asecret)
      client.profile(id => self.uid)
      client.profile
    end
    
    def full_name
      linkedin_profile.first_name + " " + linkedin_profile.last_name
    end
    
    def image_url
      linkedin_profile(:fields => "picture-url").picture_url
    end
    

    【讨论】:

    • 是的,在上面的代码中,@linkedin_profile 只设置了一次,之后@linkedin_profile 中存储的对象就被使用,而无需再次调用LinkedIn API。
    • @mischa -- 你的意思是即使我去不同的控制器它也有价值?常规实例变量不保存状态等等——这有什么不同吗?谢谢...这可能就是我想找的东西(但是如果用户不同呢?
    • 不,这意味着它保存了每个请求的值。因此,如果您在单个请求中使用full_nameimage_url,API 只会被调用一次。这些是实例方法,因此将为每个用户执行不同的调用。
    • @mischa -- 对于 u.image_url -- 它说传递了错误数量的参数?
    【解决方案2】:

    我会将以下方法添加到您的用户类中:

    class User
      def linkedin_client
        @linkedin_client || = get_linkedin_client 
      end
    
      def linkedin_profile
        linkedin_client.profile(id => self.uid)
        linkedin_client.profile
      end
    
      def full_name
        linkedin_profile.first_name + " " + user.linkedin_profile.last_name
      end
    
      def image_url
        linkedin_profile(:fields => "picture-url").picture_url
      end
    
    
      private
    
      def get_linkedin_client
        client = LinkedIn::Client.new(ENV['LINKEDIN_KEY'], ENV['LINKEDIN_SECRET'])
        client.authorize_from_access(atoken, asecret)   
        client     
      end
    end
    

    在你的控制器内部你会写:

    if @review.save
      flash[:notice] = "Successfully created review."
      # check if allowed to post to LinkedIn and post
      if @review.post_linkedin?
        current_user.linkedin_client.update_network("has shared expertise on <a")
      end
    end
    

    希望这会有所帮助。

    【讨论】:

    • NoMethodError: 未定义方法 profile' for #&lt;Array:0xb64b91a8&gt; from /home/timothy/realquadrant/app/models/user.rb:30:in linkedin_profile' 来自 (irb):4
    • 嗨安吉拉,我编辑了 get_linkedin_clientlinkedin_profile 方法。我希望这会有所帮助。
    • @nathavnda,LinekdIN 客户端有点复杂,我需要再次检查...
    【解决方案3】:

    一般规则是:提取到处重复的代码,将其放入可重用的类/方法等中。

    对于上面的代码。你可以这样做:

    def get_client_profile
          client = LinkedIn::Client.new(ENV['LINKEDIN_KEY'], ENV['LINKEDIN_SECRET'])
          client.authorize_from_access(self.atoken, self.asecret)
          client.profile(id => self.uid)
          client.profile
    end
    
    def full_name
      p=get_client_profile
      p.first_name + " " + p.last_name
    end
    

    ...等

    在这种情况下,您可以在模型中拥有 get_client_profile(可能在模型客户端中?)。因为“它属于他们”。

    【讨论】:

    • @ 谢谢——如果我需要在控制器中调用相同的东西,我该怎么做?
    • of me...我认为这些方法是 User 的方法?
    • @angela 如果您将此方法放在模型中(即用户),您仍然可以从控制器(user.get_client_profile,其中用户是用户的实例)调用它。
    猜你喜欢
    • 1970-01-01
    • 2013-04-18
    • 2011-06-14
    • 1970-01-01
    • 2012-12-14
    • 2015-06-04
    • 1970-01-01
    • 1970-01-01
    • 2010-11-24
    相关资源
    最近更新 更多