/ / Об'єктно-орієнтований спосіб перевірки нуля на асоціації в рейках - ruby-on-rails, ruby

Об'єктно-орієнтований спосіб робити нульові перевірки асоціацій на рейках - рубін на рейках, рубін

Я дивився Санді Меца " ніщо - це щось презентація кілька разів.Я усвідомлюю, що в своїх проектах на рейках всюди роблю перевірки на нуль, але я не знаю, як уникнути перевірок на нуль і як це зробити об’єктно-орієнтовано, коли йдеться про асоціації.

Розглянемо ці асоціації:

#app/models/user.rb
class User < ActiveRecord::Base
belongs_to :blog
end

#app/models/blog.rb
class Blog < ActiveRecord::Base
belongs_to :hash_tag
has_one :user
end

#app/models/hash_tag.rb
class HashTag < ActiveRecord::Base
has_one :blog
end

Я захоплюю користувача:

@user = User.find(1)

І я хочу знайти його блог:

@user.blog
=> nil

Це повертається nil ось тому, що це user трапляється, що не пов’язано blog, отже, наступний код порушить роботу програми, якби я зробив щось подібне для цього user:

@user.blog.title
=> undefined method `title" for nil:NilClass

Просте виправлення полягає в тому, щоб зробити це не об’єктно-орієнтованим способом і просто виконати перевірку на нуль (але цього ми хочемо уникнути, оскільки в іншому випадку перевірки на нуль є абсолютно скрізь у програмі):

@user.blog.title if @user.blog

Виконання нульових перевірок стає більш громіздким і процедурним, чим глибше ви проникаєте через асоціації, як показано нижче:

@user = User.find(1)
if @user.blog && @user.blog.hash_tag #checking for nil twice
@user.blog.hash_tag.tag_name
end

Який об’єктно-орієнтований спосіб уникнути нульових перевірок асоціацій?

Мені відомі рейки " спробувати метод, хоча Мец, здається, не рекомендував try метод. Можливо, якщо мова йде про асоціації в рейки: try це найкращий варіант?

Відповіді:

6 за відповідь № 1

Існує так звана настанова щодо програмування Закон Деметри

Ось як застосувати його до своїх моделей рейок:

#app/models/user.rb
class User < ActiveRecord::Base
belongs_to :blog
delegate :title, to: :blog, prefix: true, allow_nil: true
# then you can call user.blog_title
delegate :tag_name, to: :blog, prefix: true, allow_nil: true
# follow LoD
end

#app/models/blog.rb
class Blog < ActiveRecord::Base
belongs_to :hash_tag
delegate :tag_name, to: :hash_tag, allow_nil: true
has_one :user
end

І тепер ви можете зробити це:

@user = User.find(1)
@user.blog_title # no error even if there is no associated blog
@user.tag_name # no error even if there is no associatd blog or no associated hash_tag object

Будь ласка, прочитайте наступне посилання для посилань:


2 для відповіді № 2

Є чудова перлина andand який я використовую у подібних випадках. Зазвичай вам потрібно написати:

@user.blog && @user.blog.title

andand gem реалізує загальний нульовий шаблон. andand розширює Object методом andand, який повертає об'єкт, до якого його викликали, якщо він не дорівнює нулю. У разі значення nil повертається об'єкт NullPatern, щоб повернути значення nil для всіх викликів методів, використовуючи метод magic_missing magic.

@user.blog.andand.title

Це ще потужніше, коли потрібно перевірити більше умов:

@user.blog && @user.blog.title && @user.blog.title.capitalize

стає:

@user.blog.andand.title.andand.capitalize

1 для відповіді № 3

Я думаю, що це можуть бути варіанти

Я б хотів: rescue метод
Обережно: цей метод вловлює винятки і відповідає відповідно; Не використовуйте це, якщо вам потрібно по-іншому реагувати на винятки. Сподіваюся, ви розумієте

@user = User.find(1)
tag_name = @user.blog.hash_tag.tag_name rescue "" # respond with default value

Приклад:

2.1.1 :001 > var1 = nil
=> nil
2.1.1 :002 > my_val = var1.some_method

NoMethodError: undefined method `some_method" for nil:NilClass
from (irb):2
from /home/shiva/.rvm/rubies/ruby-2.1.1/bin/irb:11:in `<main>"

2.1.1 :003 > my_val = var1.some_method rescue ""
=> ""

Іншим варіантом було б .try метод; http://apidock.com/rails/Object/try

.try визначено в Rails тому не бути доступним поза Rails

@person.non_existing_method if @person.respond_to?(:non_existing_method)
# instead use
@person.try(:non_existing_method) # => returns nil if does not respond_to

try повертає nil при виклику nil незалежно від того, чи відповідає він методу:

nil.try(:to_i) # => nil, rather than 0