it-swarm.com.ru

Когда использовать себя в модели?

Вопрос: когда мне нужно использовать self в моих моделях в Rails?

У меня есть метод set в одной из моих моделей.

class SomeData < ActiveRecord::Base
  def set_active_flag(val)
    self.active_flag = val
    self.save!
  end
end

Когда я делаю это, все работает нормально. Тем не менее, когда я делаю это:

class SomeData < ActiveRecord::Base
  def set_active_flag(val)
    active_flag = val
    save!
  end
end

Значение active_flag не изменяется, скорее оно молча завершается сбоем. Может кто-нибудь объяснить?

Я не могу найти дубликаты, но если кто-то найдет, это тоже хорошо.

66
varatis

Когда вы выполняете действие над экземпляром, который вызывает метод, вы используете self.

С этим кодом

class SocialData < ActiveRecord::Base
  def set_active_flag(val)
    active_flag = val
    save!
  end
end

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

self.active_flag = val

Однако сообщает экземпляру изменить свой собственный атрибут с именем active_flag вместо совершенно новой переменной. Вот почему это работает.

59
DVG

Это происходит из-за ограниченности. Когда вы находитесь внутри метода и пытаетесь установить новую переменную, подобную этой:

class SomeData < ActiveRecord::Base
  def set_active_flag(val)
    active_flag = val
  end
end

Вы создаете совершенно новую переменную, которая живет внутри set_active_flag. Как только это будет выполнено, оно исчезнет, ​​не изменяя self.active_flag (фактическую переменную экземпляра) каким-либо образом.

ОДНАКО (это было источником путаницы для меня): когда вы пытаетесь читать переменную экземпляра в Ruby, например так:

class SomeData < ActiveRecord::Base
  def whats_my_active_flag
    puts active_flag
  end
end

Вы фактически получите self.active_flag (фактическая переменная экземпляра).


вот почему:

Ruby сделает все возможное, чтобы не возвращать nil.

  1. Первоначально он спрашивает "существует ли active_flag в пределах whats_my_active_flag?"
  2. Он ищет и понимает, что ответ "нет", поэтому он переходит вверх один уровень, к экземпляру SomeData
  3. Он снова спрашивает то же самое: "active_flag существует в этой области?
  4. Ответ "да", и поэтому он говорит: "У меня есть кое-что для тебя", и это возвращает это!

Однако, если вы определяете active_flag в whats_my_active_flag, а затем запрашиваете его, он снова проходит через шаги:

  1. Он спрашивает "существует ли active_flag в пределах whats_my_active_flag?
  2. Ответ "да", поэтому он возвращает это значение

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

Простой способ описать это поведение - "он не хочет вас разочаровывать" и вернуть nil - поэтому он делает все возможное, чтобы найти все, что может.

В то же время "он не хочет портить данные, которые вы не собирались изменять", поэтому он не изменяет саму переменную экземпляра.

Надеюсь это поможет!

51
Yuval Karmi

Это чтобы убедиться, что вы используете метод setter, а не определяете область видимости новой переменной. Это Ruby и ​​подробности использования AR, которые часто приводят людей в замешательство (другое - неправильное использование переменной экземпляра).

Обратите внимание, что уже есть pdate_attributes! хотя я понимаю желание абстрагироваться.

Также есть toggle! , что может быть даже лучше, в зависимости от вашего интерфейса с флагом.

1
Dave Newton

Когда вы используете active_flag = val Ruby, считая, что вы определяете локальную переменную, лучше всего self.active_flag = val, если вы ее получили, надеюсь, вы знаете, что send(:active_flag=, val) будет работать тоже.

0
fangxing