Как сделать метод доступным для моего контроллера и модели в Rails? - PullRequest
10 голосов
/ 25 августа 2010

У меня есть частный метод в приложении Rails для подключения к Amazon S3, выполнения переданного блока кода, а затем закрытия подключения к S3.Это выглядит так:

def S3
  AWS::S3::Base.establish_connection!(
    :access_key_id     => 'Not telling',
    :secret_access_key => 'Really not telling'
  )
  data = yield
  AWS::S3::Base.disconnect
  data
end

Это называется так (в качестве примера);

send_data(S3 {AWS::S3::S3Object.value("#{@upload_file.name}",'bucket')}, :filename => @upload_file.name)

Я вызываю этот метод несколькими способами в моем контроллере и модели, поэтомуон включен в оба класса в качестве частного метода.Это прекрасно работает, и я доволен этим, но это не очень СУХОЙ.

Как я могу сделать этот метод доступным как для моей модели, так и для контроллера, но код должен появиться только один раз?Это больше вопрос Ruby, чем вопрос Rails и отражает мою новизну в ООП.Я предполагаю, что ответом является модуль или дополнение, но я до сих пор не использовал ни один из них и мне нужно немного подержать.

Спасибо.

Ответы [ 3 ]

9 голосов
/ 25 августа 2010

Модули используются для 3 разных вещей в рубине. Во-первых, пространство имен. Наличие определений классов или констант внутри модуля не будет конфликтовать с классами или константами вне этого модуля. Как то так

class Product
  def foo
    puts 'first'
  end
end

module Affiliate
  class Product
    puts 'second'
  end
end

p = Product.new
p.foo # => 'first'

p = Affiliate::Product.new
p.foo # => 'second'

Второе использование для модулей - это место, где можно придерживаться методов, которые на самом деле не имеют места где-либо еще. Вы можете сделать это и внутри класса, но с помощью модуля своего рода люди, читающие код, говорят, что он не предназначен для реализации. Как то так

module Foo
  def self.bar
    puts 'hi'
  end
end

Foo.bar #=> 'hi'

Наконец (и самое запутанное) это то, что модули могут быть включены в другие классы. Их использование также называется миксином, потому что вы «смешиваете» все методы во все, что вы включаете.

module Foo
  def bar
    puts 'hi'
  end
end

class Baz
  include Foo
end

b = Baz.new
b.bar #=> 'hi'

Миксины на самом деле более сложная тема, чем я здесь освещаю, но углубление, вероятно, может сбить с толку.

Теперь, мне кажется, что S3 действительно принадлежит контроллеру, поскольку контроллеры, как правило, относятся к входящим и исходящим соединениям. Если это так, я бы просто использовал защищенный метод на контроллере приложения, так как он будет доступен для всех других контроллеров, но все равно будет закрытым.

Если у вас есть веская причина для того, чтобы он тоже был в модели, я бы выбрал миксин. Что-то вроде

module AwsUtils
private
  def S3
    AWS::S3::Base.establish_connection!\
      :access_key_id     => 'Not telling',
      :secret_access_key => 'Really not telling'

    data = yield
    AWS::S3::Base.disconnect
    data
  end
end

Если вы введете это в lib/aws_utils.rb, вы сможете использовать его, добавив include AwsUtils и в свой контроллер, и в свою модель. Rails знает, как искать классы и модули в lib, но только если имя совпадает (в широком случае). Я назвал это AwsUtils, потому что я знаю, что rails будет искать, когда он это увидит (aws_utils.rb), и, честно говоря, я понятия не имею, что ему понадобится для S3Utils; -)

Не стесняйтесь спрашивать дополнительную информацию, если мне что-то неясно. Модули, как правило, являются одной из тех вещей в ruby, которые, хотя и удивительны, просто сбивают с толку новичков.

3 голосов
/ 25 августа 2010

Ваша догадка верна: вы можете поместить модуль в каталог lib. В Чтобы сделать эти методы доступными для ваших моделей, просто включите их с:

class Model < ActiveRecord::Base
  include MyModule
end

Методы экземпляра включенного модуля станут методами экземпляра в вашем классе. (Это называется миксин)

module MyModule
  def S3
    #...
  end
end
1 голос
/ 25 августа 2010

Вы можете написать модуль как:

module MyModule
  def self.S3(args*)
    AWS::S3::Base.establish_connection!(
      :access_key_id     => 'Not telling',
      :secret_access_key => 'Really not telling'
    )
    data = yield
    AWS::S3::Base.disconnect
    data
  end
end

и затем назовите его в вашем контроллере или модели как

MyModule.S3 (PARAMS *)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...