Лучшие практики Rails — контроллер или модель?

Я хочу использовать этот фрагмент кода для получения списка кредитных карт пользователя в файле с Stripe для отображения в его профиле (/users/:id)

@stripe_cards = Stripe::Customer.retreive(self.stripe_customer_id).cards.all

Дело в том, что я не совсем уверен, где (с точки зрения лучших практик Rails) это подходит. Моя первая задача — поместить его в метод show пользовательского контроллера, так как это не совсем бизнес-логика и не вписывается в модель. Я также просмотрел вспомогательные методы, но, насколько я понимаю, они, похоже, используются строго при игре с HTML.

Кто-нибудь из вас, экспертов по Rails, может присоединиться?

Спасибо! Фрэнсис


person Francis Ouellet    schedule 04.12.2013    source источник
comment
метод show пользовательского контроллера выглядит нормально для меня   -  person Siva    schedule 04.12.2013
comment
Я бы, наверное, поставил на Custom аксессор, который берет id пользователя и возвращает карточки (то есть, если я правильно понимаю ваши модели). Тогда в контроллере не нужно было бы вызывать retrieve или карты. Кроме того, все ли необходимо?   -  person kddeisz    schedule 04.12.2013
comment
@musicnerd47musicnerd47 Не могли бы вы рассказать подробнее об упомянутом вами аксессуаре Custom? Кроме того, я использую .all прямо сейчас и знаю, что в долгосрочной перспективе это может вызвать проблемы, но сомневаюсь, что у пользователей может быть столько действительных кредитных карт в файле :)   -  person Francis Ouellet    schedule 04.12.2013
comment
Правильно, но вам не нужно звонить всем, это должно просто работать. Кроме того, я имел в виду аксессор на Customer   -  person kddeisz    schedule 04.12.2013
comment
Да, я удалил .all по вашему совету. Кроме того, я рассмотрю аксессуары. Чем они лучше методов?   -  person Francis Ouellet    schedule 04.12.2013


Ответы (2)


Хороший вопрос. Всякий раз, когда вы видите переменную экземпляра в rails (начиная с @), это обычно бит кода представления/контроллера.

@stripe_cards = Stripe::Customer.retreive(self.stripe_customer_id).cards.all

Однако, глядя на конец этого

Stripe::Customer.retreive(self.stripe_customer_id).cards.all

Это может лучше подходить для модели, где вы можете повторно использовать одну и ту же строку, но при этом обеспечиваете безопасность дополнительной обработки ошибок и предсказуемого поведения. Например

# user.rb

def stripe_customer_cards
  Stripe::Customer.retreive(self.stripe_customer_id).cards.all
  rescue Stripe::InvalidRequestError
    false # You could use this to render some information in your views, without breaking your app.
end

Также обратите внимание на использование self. Обычно это подразумевает использование модели Rails, потому что вызов self в контроллере на самом деле относится к контроллеру, что делает его почти бесполезным, если вы действительно не знаете, что делаете.

ИЗМЕНИТЬ

Чтобы отобразить сообщение об ошибке, просто напишите вызов для перенаправления или рендеринга с параметром alert.

if @stripe_cards = current_user.stripe_customer_cards
  # Your being paid, sweet!
else
  # Render alert info :(
  render 'my_view', alert: 'This is an alert'
  redirect_to other_path, alert: 'Another alert'
end

Я также хотел бы отметить, что вы не должны обрабатывать ошибки только потому, что можете. Не обрабатывайте ошибки, которых не ожидаете. Если вы обрабатываете ошибки, которых не ожидаете,

  • Запутать пользователей
  • Затруднить исправление ошибок в коде
  • Преувеличивать время до обнаружения ошибки
person OneChillDude    schedule 04.12.2013
comment
Придирка: @ не указывает на глобальную переменную, она указывает на переменную области экземпляра класса. Глобальные переменные начинаются с $, и вы (надеюсь) редко встретите их в приложениях Rails. @@ относится к классу (или в некоторых случаях к модулю), аналогично статической переменной в других языках. - person JasonTrue; 04.12.2013
comment
@bwheeler96 bwheeler96 Спасибо за отличный ответ, я не учел часть обработки ошибок, когда публиковал вопрос. Говоря об этом, я не уверен, что понимаю, как я мог отобразить это на мой взгляд. Я использую флэш-сообщения прямо сейчас с предупреждениями Bootstrap. - person Francis Ouellet; 04.12.2013
comment
Обработка ошибок в представлении — это долгий разговор, а предупреждение начальной загрузки — отличный вариант для большинства случаев. - person OneChillDude; 05.12.2013
comment
@ bwheeler96 Спасибо за ваше редактирование, очень признателен. Теперь у меня есть лучшее понимание. Однако возникает другой вопрос: не хотел бы я получить точное сообщение об ошибке от Stripe и отобразить его пользователю? - person Francis Ouellet; 07.12.2013
comment
Фрэнсис, отвечая на ваш вопрос, подумайте: что, если эта ошибка возникнет по неожиданной причине и будет обнаружена, возникнут ли проблемы? Если ответ положительный, не перехватывайте исключение. Вы можете делать со своим кодом все, что хотите, я просто не хочу, чтобы другие разработчики стреляли себе в ногу. - person OneChillDude; 09.12.2013
comment
Привет @bwheeler96, еще раз спасибо за ваш вклад. Большое спасибо! - person Francis Ouellet; 12.12.2013
comment
Нет проблем, я ценю возможность помочь, когда я могу. - person OneChillDude; 12.12.2013

Я бы рекомендовал добавить виртуальный атрибут в вашу модель User:

# app/models/user.rb
def cards
    Stripe::Customer.retrieve(stripe_customer_id).cards.all # note the spelling of `retrieve`
end

Затем вы сможете получить доступ ко всем карточкам пользователей следующим образом:

user = User.first
#=> #<User id:1>

user.cards
#=> [Array of all cards]
person zeantsoi    schedule 04.12.2013