#ruby-on-rails #ruby #rubygems
#ruby-on-rails #ruby #rubygems
Вопрос:
У меня ситуация, когда мне нужно вызвать что-то вроде этого :
class Office
attr_accessor :workers, :id
def initialize
@workers = []
end
def workers worker
type = worker.type
resp = Worker.post("/office/#{@id}/workers.json", :worker => {:type => type})
worker = Worker.new()
resp.to_hash.each_pair do |k,v|
worker.send("#{k}=",v) if worker.respond_to?(k)
end
self.workers << worker
end
end
Рабочий класс
class Worker
attr_accessor :office_id, :type, :id
def initialize(options={})
@office_id = options[:office].nil? ? nil : options[:office].id
@type = options[:type].nil? ? nil : options[:type].camelize
if !@office_id.nil?
resp = self.class.post("/office/#{@office_id}/workers.json", :worker => {:type => @type})
@id = resp.id
office = options[:office]
office.workers = self
end
end
def <<(worker)
if worker
type = worker.type
resp = Worker.post("/office/#{office_id}/workers.json", :worker => {:type => type})
debugger
@id = resp.id
resp.to_hash.each_pair do |k,v|
self.send("#{k}=",v) if self.respond_to?(k)
end
debugger
return self
end
end
Я могу сделать что-то подобное очень хорошо
office = Office.new()
new_worker = Worker.new()
office.workers new_worker
Но мне нужно сделать то же самое, что я сделал выше, например, следующим образом. Перед этим мне нужно изменить метод инициализации Office, чтобы запустить def <<(worker)
метод экземпляра worker.
class Office
...
def initialize
@workers = Worker.new
@workers.office_id = self.id
end
office = Office.new()
new_worker = Worker.new()
office.workers << new_worker
Теперь проблема в том, что более поздняя реализация создает 2 экземпляра worker??
Комментарии:
1. @zabba, он добавляет новый объект worker в атрибуты worker объекта office, а атрибутом worker является массив.
2. Вы изменили больше кода, чем просто это? Как есть, office. workers << new_worker должен быть аргументом ошибки начиная с office. workers — это метод, принимающий 1 параметр.
3. @Джеймс, нет, эта часть в порядке.
4. кстати, «if !worker.nil?» лучше выразить как «если рабочий»
5. @джеймс, да, но проблема не в этом
Ответ №1:
Я не совсем уверен, но я полагаю, вы хотели бы иметь это:
class Office
attr_accessor :workers, :id
def initialize
@workers = []
end
alias_method :workers, :return_worker_array
def workers worker
unless worker
return_worker_array
else
type = worker.type
resp = Worker.post("/office/#{@id}/workers.json", :worker => {:type => type})
worker = Worker.new()
resp.to_hash.each_pair do |k,v|
worker.send("#{k}=",v) if worker.respond_to?(k)
return_worker_array << worker
end
end
завершение
Таким образом, вы можете полностью избавиться от Worker#<<
, и вам также следует удалить строку
office.workers = self
предполагается, что in Worker#initialize
since office.workers
является массивом. Менять тип атрибута взад и вперед — плохая идея (можно вводить утку), потому что, скорее всего, вы потеряете отслеживание текущего состояния и рано или поздно столкнетесь с ошибками.
Чтобы следовать «разделению проблем», я бы рекомендовал выполнять все управление workers
исключительно в Office
, иначе это слишком быстро запутывается и будет намного сложнее поддерживать в долгосрочной перспективе.
Ответ №2:
Я не уверен на 100%, почему вы здесь не получаете ошибку, но поскольку последней строкой Office#workers является self.workers << worker, вы добавляете нового worker, созданного в Office #workers (созданного в 3-й строке метода), а затем возвращаете объект workers, который затем снова вызывается #<< для него с новым worker, созданным вне метода
Комментарии:
1. да, вот почему его перепутали, чтобы реализовать это …. так что есть идеи, как я могу реализовать #<< метод при вызове
office.workers << new_worker
, как я сделал вoffice.workers new_worker
2. я бы выбрал другое имя для атрибута, чтобы вы могли выполнять
office.workers new_worker
иoffice.new_worker_name << new_worker
. В идеале я бы выбралoffice.add_worker new_worker
иoffice.workers << new_worker
, но, похоже, у вас есть устаревший код для поддержки, поэтому вы не хотите изменять предыдущие вызовы. (Я знаю, это не то, о чем вы просили, но именно так я бы это сделал. Если бы вы лучше объяснили сценарий, я мог бы дать другой ответ)3. Я просто хочу, чтобы более поздний метод функционировал так же, как я делал в предыдущем, и с тем же именем. когда я вызываю
office.workers << new_worker
, он просто вызывает атрибут получения / установки workers по умолчанию.