#ruby-on-rails #ruby
#ruby-on-rails #ruby
Вопрос:
Разработка в Rails 5.2.2.1. Я хочу определить «глобальный» обработчик восстановления для моей модели, чтобы я мог перехватывать NoMethodError
и предпринимать соответствующие действия. Я обнаружил, что контроллеры могут делать это с rescue_from
, но модели не могут. Зная, что разработчики Rails — умные люди 😉 Я полагаю, для этого должна быть какая-то веская причина, но я все еще расстроен. Погуглил, и я даже не могу найти ни одного примера, когда люди спрашивали, как это сделать, а другие люди либо рассказывали им, как, либо почему они не могут, либо почему они не должны хотеть. Может быть, это потому, что обработчики rescue не могут вернуть значение исходному вызывающему?
Вот что я пытаюсь сделать: мне нужно провести рефакторинг моего приложения, чтобы то, что раньше было одной моделью, теперь было разделено на две (давайте назовем их Orig и New). Вкратце, я хочу сделать так, чтобы при вызове метода получения атрибута (скажем) для исходного объекта, если этот атрибут переместился в New, я мог перехватить эту ошибку и вызвать new.getter
вместо этого (понимая, что Origin теперь belongs_to
новый). Это решение основано на моем опыте выполнения подобных действий с AUTOLOAD
функцией Perl5.
Любые идеи о том, как это сделать, высоко ценятся. Может быть, мне просто нужно определить получатели / установщики для всех перемещаемых атрибутов по отдельности.
Комментарии:
1. Люди разрабатывают решения на основе того, что они уже знают. Слова «делегирование» не было в моем словаре s / w разработчиков, и никакое количество поисковых запросов в Google о том, как отлавливать ошибки без метода, не могло найти его для меня. Спасибо, что предоставили полезный совет и совсем не ехидничаете.
Ответ №1:
Переопределите метод_миссинга 🙂 !?
Вы могли бы попробовать переопределить method_missing
метод. Это потенциально может привести к запутанным ошибкам, но переопределение этого метода определенно используется с большим эффектом по крайней мере в одном gem, о котором я знаю.
Я не хотел вызывать класс new
, потому что это зарезервированное ключевое слово и может сбивать с толку. Итак, я изменил имя класса на Upgraded
.
Это должно помочь вам начать.
class Upgraded
def getter
puts "Congrats, it gets!"
end
end
class Original
def initialize
@new_instance = Upgraded.new
end
def method_missing(message, *args, amp;block)
if message == :attribute_getter
@new_instance.send(:getter, *args, amp;block)
else
super
end
end
def respond_to_missing?(method_name, *args)
method_name == :attribute_getter or super
end
end
c = Original.new
c.attribute_getter
- Вам придется изменить имена методов получения и установки. Поскольку у вас есть
belongs_to
ассоциация, вы можете просто использовать это.
Или вы могли бы попробовать просто использовать delegate_to
как предлагает @mu_is_too_short, вы могли бы попробовать что-то подобное?
class Original < ApplicationRecord
belongs_to :upgraded
delegate :getter_method, :to => :upgraded
end
class Upgraded < ApplicationRecord
def getter_method
end
end
Комментарии:
1. Определенно было бы осторожнее с указанным параметром «Метод отсутствует» github.com/rails/rails/blob/master/activerecord/lib /… и github.com/rails/rails/blob/master/activemodel/lib/active_model /…
Ответ №2:
Очевидно, что мне нужно было знать слово «делегирование«. Кажется, есть множество способов сделать такого рода вещи в Ruby и Rails, и я должен был ожидать, что способ Ruby сделать это будет более чистым, элегантным и более развитым, чем Perl5. В частности, последние версии Rails предоставляют «delegate_missing_to«, который, похоже, является именно тем, что мне нужно для этого варианта использования.