Объекты передачи данных VS Объекты домена/ActiveRecord в представлении в RoR

Я исхожу из фона .NET, где принято не привязывать модели домена/сущности непосредственно к представлению в не очень простых CRUD-приложениях, где представление не проецирует напрямую поля сущности как есть.

Мне интересно, какова практика в RoR, где механизмом сохранения по умолчанию является ActiveRecord. Я бы сказал, что информация, связанная с презентацией, не должна передаваться сущностям, хотя не уверен, что настоящие главы RoR поступили бы так.

Если DTO/модель для представления является подходом, как вы будете делать это в Rails?

Твои мысли?

ИЗМЕНИТЬ:

Некоторые примеры:
 – В представлении отображается список счетов-фактур с количеством уникальных элементов в одном столбце.
 – Список счетов кредитных карт, по которым, возможно, были выполнены мошеннические операции. Для этого пользовательский интерфейс должен отображать эту строку красным цветом.

В обоих сценариях в списках отображаются не все поля сущностей, а лишь некоторые из них, отображаемые в списке (например, номер счета, дата транзакции, имя учетной записи, сумма транзакции).

В примере со счетом-фактурой объект счета-фактуры не имеет сопоставленного с ним поля «Количество позиций». База данных не была денормализована по соображениям производительности, и она будет вычисляться во время запроса с использованием агрегатных функций.

Для примера со счетами кредитных карт, конечно же, объект транзакции карты не имеет инварианта «Показать в красном» или «Является мошенническим». Да, это может быть бизнес-правилом, но для этого примера это проблема представления, поэтому я хотел бы не допустить его в свою модель предметной области.


person leypascua    schedule 23.02.2010    source источник
comment
У меня нет опыта работы с .NET, и, возможно, я не так хорошо образован - и я не понимаю вашего вопроса. Не могли бы вы привести несколько примеров?   -  person klew    schedule 24.02.2010
comment
Я нахожу ваш вопрос очень полезным, ясным и точным, однако я не думаю, что термин DTO является правильным термином для того, что вы описываете. DTO — это Объект передачи данных, термин, используемый в архитектурах клиент-сервер для объекта связи, которым обмениваются клиент и сервер, тогда как то, что вы описываете, обычно называется ViewModel, то есть модель, предназначенная для привязки к представлению.   -  person Boris B.    schedule 13.02.2014


Ответы (1)


В целом я бы ответил, что ваш объект AcitveRecord может содержать любые поля и вы показываете в представлениях только то, что хотите. В сценариях rails есть задача создания каркаса, но она предназначена только для создания некоторой модели установки, контроллера и представления. Когда я работаю с Rails, я вообще не использую ./script/generate scaffold. Скорее я генерирую только модель и контроллер отдельно. Часть просмотра я добавляю вручную.

ActiveRecord только сопоставляет данные из базы данных с некоторыми красивыми объектами. Что вы будете делать с этим в поле зрения, зависит от вас.

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

Для вашего примера счета я бы создал представление следующим образом:

<h1>Invoices</h1>
<table>
  <tr>
    <th>Invoice #</th>
    <th>Date</th>
    <th>Name</th>
    <th>No. of line items</th>
    etc
  </tr>
  <% @invoices.each do |invoice| %>
    <tr>
      <td><%= invoice.number %></td>
      <td><%= invoice.date.to_s %></td>
      <td><%= invoice.name %></td>
      <td><%= invoice.line_items.count %></td>
      etc.
    </tr>
  <% end %>
</table>

Или даже поместите строку с данными счета в отдельный раздел и отобразите ее в представлении выше. Я предполагаю, что в вашей модели у вас есть:

# Invoice model
has_many :line_items

Теперь давайте посмотрим на примере кредитной карты. Я бы сделал это так:

# In CreditCard model add method
def fraudulent?
  #put here some logic that returns true or false
end

Затем, по вашему мнению, при отображении этой кредитной карты:

<div <%= @credit_card.fraudulent? ? 'class="show_in_red"' : '' %>
   here you can show whatever you want
</div>

Или даже создать для него хелпер:

# credit card helper
def add_show_in_red(credit_card)
  credit_card.fraudulent? ? 'class="show_in_red"' : ''
end

# in Rails 3 or earlier version with plugin that puts `h` method by default 
# your helper should have additional safe_html! call
def add_show_in_red(credit_card)
  (credit_card.fraudulent? ? 'class="show_in_red"' : '').safe_html!
end

и на виду:

<div <%= add_show_in_red(@credit_card) %>>
   here you can show whatever you want
</div>
person klew    schedule 24.02.2010
comment
Доступ к invoice.line_items.count возможен, если данных относительно мало. В сценариях, где список дочерних сущностей огромен, это, безусловно, сильно скажется на производительности. Credit_card.fraudulent - это то, что я пытаюсь предотвратить, если у меня есть более одного варианта использования, в котором используется сущность кредитной карты, это заставляет меня помещать весь логический код, связанный с презентацией, в мою сущность, загрязняя мою сущность пользовательским интерфейсом, обеспокоенность. Например, в случае использования обновления кредитной карты мне не понадобится флаг Мошенничество. Это приведет к тому, что класс станет неконтролируемо большим, поскольку каждый может добавлять к нему инварианты. - person leypascua; 25.02.2010
comment
Для подсчета элементов вы можете использовать counter_cache - он будет хранить количество в родительском объекте, поэтому это не вызовет дополнительной нагрузки на базу данных. Как я понимаю это credit_card.fraudulent - это не презентация. Это какое-то «состояние» кредитной карты, поэтому оно принадлежит модели (насколько я понимаю). В Rails объект ActiveRecord всегда довольно большой и содержит много вещей, которые я не использую. Насколько я знаю, людей в «мире» Rails это не волнует. Если вам не нужно использовать credit_card.fraudulent в каком-то представлении, просто игнорируйте его, притворяйтесь, что его здесь нет. Но если вы действительно хотите его отделить, добавьте всю логику в помощник. - person klew; 25.02.2010
comment
Но для меня это без необходимости сломает MVC - person klew; 25.02.2010
comment
Credit_card.fraudulent является инвариантом — его значение оценивается каждый раз, когда к нему обращаются. В этом примере да, это не презентация, поскольку .fraudulent может быть получен из списка подозрительных транзакций. Но что, если вы показываете сетку, в которой один столбец показывает доступные действия для строки, а действия различаются из-за какого-то инварианта, то вы начнете загрязнять класс. Для небольших команд, которые работают долгое время, это может не быть проблемой. Он становится одним, когда у вас появляются новые члены, когда контроль начинает исчезать. - person leypascua; 25.02.2010
comment
Мне трудно понять вашу проблему. Может быть, это потому, что у меня нет опыта работы с электронной коммерцией и я не «чувствую» то, о чем вы говорите. Может быть, если бы ваши примеры могли быть более точными (например, привести некоторые данные, значения и показать, что вы хотите получить от этого), было бы проще. И если вы не хотите оценивать значение fraudulent при каждом запросе, вы можете сохранить его в БД - я не вижу здесь другого решения. - person klew; 26.02.2010