Извлечение аргументов в класс - PullRequest
0 голосов
/ 27 января 2020

Я ищу лучший способ извлечь класс из списка аргументов, который стал слишком длинным в одном из моих сервисов. Я попытался следовать нескольким статьям и сообщениям здесь, но не повезло. Мой код:

app / services / location / update_event.rb

class Location::UpdateEvent
  def self.call(location:, event_id:, created_by:, city_details: nil, city_description: nil, city_weather: nil, city_location: nil )
    # Would like to to extract the above city arguments into its own class called city_info

    ActiveRecord::Base.transaction do
      LocationEvent.create(
        event: Event.find(event_id),
        location: location,
        # Here is where this data is then being sent to another servixe
        city_details: city_details,
        city_description: city_description,
        city_weather: city_weather,
        city_location: city_location,
        entered_at: Time.zone.now
      )
    end
  end
end

Вот что я попробовал, и заменил 4 аргумента на city_info: в update_location .rb.

app / services / event / city_info.rb

class CityInfo
  attr_accessor :city_details, :city_description, :city_weather, :city_location

  def initialize(
    city_details: nil,
    city_description: nil,
    city_weather: nil,
    city_location: nil)

    @city_details = city_details
    @city_description = city_description
    @city_weather = city_weather
    @city_location = city_location
  end
end

И, наконец, вот метод обновления от контроллера, который изначально принимает параметры, и отправляет их в сервис. Они должны быть в состоянии быть ноль в случае.

def update
  authorize(location)
  @location = Location::UpdateEvent.call(
    location: location,
    event_id: params[:event_id],
    created_by: current_user,
    city_details: params[:city_details],
    city_description: params[:city_description],
    city_weather: params[:city_weather],
    city_location: params[:city_location]
  )

  @location.reload
  @location  = LocationDecorator.new(@location)
end

Ответы [ 2 ]

1 голос
/ 27 января 2020

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

CityInfo = Struct.new(:details, :description, :weather, :location, keyword_init: true)

class Location::UpdateEvent
  def self.call(location:, event_id:, created_by:, city_info: CityInfo.new)
    city_info = city_info.to_h

    ActiveRecord::Base.transaction do
      LocationEvent.create(city_info.merge(
        event: Event.find(event_id),
        location: location,
        entered_at: Time.zone.now
      ))
    end
  end
end

контроллер:

def update
  authorize(location)
  city_info = CityInfo.new(city_info_params)

  @location = Location::UpdateEvent.call(
    location: location,
    event_id: params[:event_id],
    created_by: current_user,
    city_info: city_info
  )

  @location.reload
  @location  = LocationDecorator.new(@location)
end

private

def city_info_params
  params
    .permit(:city_details, :city_description, :city_weather, :city_location)
    .transform_keys { |key| key.delete_prefix('city_') }
end

Вам нужно Ruby 2,5 или выше, чтобы использовать опцию :keyword_init Struct#new и String#delete_prefix.


Предпочтительно, чтобы параметры не начинались с city_ для начала, но я не знаю, если это вариант.

Когда вы создаете элементы формы с именами:

<input name="city[details]" type="..." value="..." />
def city_info_params
  params
    .fetch(:city, ActionController::Parameters.new)
    .permit(:details, :description, :weather, :location)
end

Тогда будет достаточно.

1 голос
/ 27 января 2020

Вы можете использовать ха sh в качестве аргумента.

class CityInfo
  attr_accessor :city_details, :city_description, :city_weather, :city_location

  def initialize(args = {})
    args.each do |k,v|
      instance_variable_set(:"@#{k}", v);
    end 
  end
end

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

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