ruby / rails: как правильно ссылаться на some_user.user_profile.name, если у пользователя еще нет user_profile? - PullRequest
1 голос
/ 28 января 2012

Как правильно обращаться к current_user.user_profile.name, когда для определенного пользователя может быть или не быть запись user_profile?

У меня есть две таблицы: User (: email) и UserProfile (: name,: company).

Пользователь has_one user_profile и UserProfile belongs_to Пользователь

Профиль может существовать или не существовать.(Это необязательно для пользователей)

Во многих моих кодах и представлениях я хочу отобразить имя пользователя и компанию, например current_user.user_profile.name

Конечно, если пользователь не создал ихв профиле current_user.user_profile равен nil, поэтому ссылка на current_user.user_profile.name приводит к ошибке.

Я знаю, как это сделать неправильно (проверяйте nil перед обращением к полю .name КАЖДЫЙ раз, когда мне нужноname).

Лучшее, что я могу придумать, - это создать метод User с именем name, который выполняет проверку nil, поэтому current_user.name возвращает имя (или "", если профиль отсутствует).Но это тоже неправильно, так как мне нужно написать метод для каждого поля, которое я добавляю в user_profile.

Ответы [ 6 ]

4 голосов
/ 28 января 2012

Я согласен с ответами Закона Деметры, но в Rails есть удобный способ для вашего класса User делегировать: name и другие методы в свой user_profile:

class User < ActiveRecord::Base
    has_one :user_profile

    delegate :name, :email, :phone, :height, :etc,
        to: :user_profile, allow_nil: true, prefix: :profile

end

Теперь вот эти:

user.profile_name
user.profile_email
user.profile_phone

вернет ноль, если user.user_profile равно нулю, а в противном случае вернет user.user_profile.name, user.user_profile.email и user.user_profile.phone соответственно. Но они скрывают этот факт от абонентов, которые взаимодействуют только с Пользователем. Вы можете оставить опцию префикса, если вы предпочитаете:

user.name
user.email
user.phone

В общем, я бы избегал стратегий, включающих исключения или rescue, если только nil user_profile не является чем-то, что не должно происходить. И я бы не хотел использовать andand или попробовать, потому что они возлагают ответственность за управление user_profile на вызывающих абонентов.

1 голос
/ 28 января 2012

Вы могли бы сделать что-то подобное, что должно работать со всеми атрибутами UserProfile:

# User.rb
def try_this(attribute)
  self.user_profile ? self.user_profile.send(attribute) : "Not Available"
end

Тогда вы просто позвоните

current_user.try_this(:name)

Редактировать

Метод Дилана try также работает:

def try_this(attribute)
  self.user_profile.try(attribute) || "Not Available"
end
1 голос
/ 28 января 2012

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

Каждый юнит должен иметь только ограниченные знания о других юнитах: только юниты, «тесно связанные» с текущим юнитом.

Итак ...

class User < ActiveRecord::Base

   def user_name
      user_profile ? user_profile.name : ""
   end

[...]
end
1 голос
/ 28 января 2012
current_user.andand.user_profile.name || "Not Available"

"andand" gem реализует нулевое безопасное сцепление.

Как вы предлагаете, создание метода User.name может быть предпочтительным (и Demeter был бы горд).

1 голос
/ 28 января 2012

Вы можете использовать try:

current_user.user_profile.try(:name) || "Not Available"

Когда вы используете rescue, существует риск того, что вы можете избавиться от ошибки другого типа, чем NoMethodError в результате user_profile, являющегося nil.

0 голосов
/ 28 января 2012

current_user.user_profile.name rescue "Not Available"

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