Метод Rails, игнорирующий параметр по умолчанию — ПОЧЕМУ?

#ruby-on-rails #ruby-on-rails-3 #methods #parameter-passing

#ruby-on-rails #ruby-on-rails-3 #методы #передача параметра

Вопрос:

Я в недоумении относительно того, почему это происходит. У меня есть следующая функция:

 def as_json(options = {})
  json = {
    :id => id,
    # ... more unimportant code
    }
  unless options[:simple]
    # ... more unimportant code
  end
  json  
end
  

Это работает большую часть времени, но в одной конкретной части, где я вызываю это:

 window.JSONdata = <%= @day.to_json.html_safe %>
  

Я получаю следующую ошибку:

ActionView::Template::Ошибка (У вас есть объект nil, когда вы этого не ожидали! Возможно, вы ожидали экземпляр Array. Ошибка произошла при вычислении nil.[]):

Указывая на строку «если параметры [:простые]». Насколько я могу судить, хэш параметров равен нулю — таким образом, метод игнорирует назначение параметра по умолчанию. ПОЧЕМУ? Я могу исправить это, изменив метод на:

 def as_json(options)
  options ||= {}
  json = {
    :id => id,
    # ... more unimportant code
    }
  unless options[:simple]
    # ... more unimportant code
  end
  json  
end
  

Имеет ли это какой-либо смысл для кого-нибудь!? Очень признателен за вашу помощь.

Ответ №1:

Это потому, что вы используете to_json , который имеет значение по умолчанию options nil . to_json в конечном итоге вызовет as_json и передаст nil как options .

Вот где это происходит в исходном коде Rails. Во-первых, to_json определяется значением по умолчанию options из nil .

 # https://github.com/rails/rails/blob/v3.0.7/activesupport/lib/active_support/core_ext/object/to_json.rb#L15
def to_json(options = nil)
  ActiveSupport::JSON.encode(self, options)
end
  

В конечном итоге он прибудет сюда.

 # https://github.com/rails/rails/blob/v3.0.7/activesupport/lib/active_support/json/encoding.rb#L41
def encode(value, use_options = true)
  check_for_circular_references(value) do
    jsonified = use_options ? value.as_json(options_for(value)) : value.as_json
    jsonified.encode_json(self)
  end
end
  

Как вы видите, as_json вызывается с помощью value.as_json(options_for(value)) и options_for(value) вернет значение по умолчанию to_json , которое nil равно.

Комментарии:

1. Большое спасибо за отличный ответ — он был действительно четким и информативным!

2. Последний вопрос. Я попытался вызвать to_json с помощью консоли, прежде чем опубликовать этот вопрос, чтобы узнать, была ли проблема с этой функцией. Однако в консоли как to_json, так и as_json работали нормально. Есть идеи, почему консоль не сгенерировала ошибку?

3. Для меня на консоли он ведет себя так, как ожидалось. Возможно, вы не перезагружали консоль, чтобы отразить код в тот момент.

4. Вероятно, вы правы насчет перезагрузки. Еще раз спасибо за помощь!