Подтвердить что ты не робот

Rails: Рефакторинг, взгляды, помощники: как все это происходит вместе?

Предупреждение: Noob здесь.

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

Например, предположим, что у меня есть:

#index.html.erb

<% for beast in @beasts do -%>
  <% if beast.dead? -%>
    <%= beast.body %>
    <%= link_to "bury", bury_beast_path( :id => beast.id ) %>
  <% else -%>
    <%= beast.body %>
    <%= link_to "kill!", kill_beast_path( :id => beast.id ) %>
  <% end -%>
<% end -%>

Мне это немного раздражает, чтобы это было на мой взгляд, но как именно я мог переместить это вместо помощника? И еще более упростите это, если это возможно. (Я где-то читал, что условные ошибки плохие, но это просто вне меня, как вы можете программировать что-либо без них.)

Другой пример: мне нужно id my body теги в формате controller_action. Самое лучшее, что я получил до сих пор:

#index.html.erb

<body id="<%= controller_action %>">

... и...

#application_helper.rb

def controller_action
  @id = @controller.controller_name + "_" + @controller.action_name
end

Я не эксперт, но это все еще уродливо даже для меня.

Чтобы усложнить ситуацию, Райан Сингер сказал что-то мне понравилось: чтобы лечить ERB как тег изображения, используя помощников, чтобы "раскрыть намерение", Затем в следующем вздохе говорят, что у вас не должно быть HTML в помощниках, потому что это путь в ад. WTF? Как обе вещи совместимы? Если дело доходит до того, что вы можете просто объявить поведение в представлении, наверняка должно быть много HTML, которые будут отображаться за кулисами? Я не могу это понять.

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

4b9b3361

Ответ 1

Рефакторинг упрощает ведение ваших представлений. Проблема заключается в выборе места для реорганизованного кода.

Ваши два варианта: частичные и помощники. Там нет правил, установленных на камне, которые должны использоваться там, где. Есть пара руководящих принципов, плавающих вокруг, как тот, который утверждает, что помощники не должны содержать HTML.

Обычно частичные части лучше подходят для разделов рефакторинга, которые больше HTML/ERB/​​HAML, чем ruby. С другой стороны, помощники используются для кусков кода ruby ​​с минимальным HTML или создания простого HTML из параметров.

Однако я не согласен с тем, что помощники вообще не должны содержать HTML. Немного в порядке, просто не делай этого. Способ обработки помощников затрудняет их использование для создания большого количества HTML. Именно поэтому он предложил, чтобы ваши помощники содержали минимальное количество HTML. Если вы посмотрите на источник, помощники, которые отправляются с рельсами, вы заметите, что большинство из них генерирует html. Немногие, которые этого не делают, в основном используются для генерации параметров и оценки общих условий.

Например, любой из помощников формы или вариантов link_to соответствует первой форме помощников. Хотя такие вещи, как url_for и logged_in? поставляемые различными моделями аутентификации, относятся ко второму виду.

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

  • Повторяющиеся или почти идентичные утверждения, производящие один неглубокий тег html? = > помощник.
  • Общее выражение используется как аргумент для другого помощника? = > помощник.
  • Длинное выражение (более 4 терминов), используемое в качестве аргумента для другого помощника? = > помощник.
  • 4 или более строк ruby ​​(которые не оцениваются в HTML)? = > помощник.
  • Довольно многое другое = > частичное.

Я собираюсь использовать код, который вы ищете для рефакторинга, в качестве примера:

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

Приложение/хелперы/beast_helper.rb:

def beast_action(beast)
  if beast.dead?
    link_to "bury", bury_beast_path(beast)
  else
    link_to "kill!", kill_beast_path(beast)
  end
end

приложение/просмотров/животные/_beast.html.erb:

<%= beast.body %>
<%= beast_action(beast) %>

приложение/просмотров/животные/index.html.erb:

<%= render :partial => "beast", :collection => @beasts %>

Это технически сложнее, потому что это 3 файла и всего 10 строк в отличие от 1 файла и 10 строк. Представления теперь состоят только из 3 строк, распределенных по 2 файлам. Конечный результат - ваш код намного более СУХОЙ. Позволяет повторно использовать части или все их в других контроллерах/действиях/представлениях с минимальной добавленной сложностью.

Что касается идентификатора тега вашего тела. Вы действительно должны использовать content_for/yield. Для этого.

приложение/просмотров/макеты/application.html.erb

...
<body id="<%= yield(:body_id) %>">
...

приложение/просмотров/животные/index.html.erb

<% content_for :body_id, controller_action %>
...

Это позволит вам переопределить идентификатор тела в любом представлении, которое его требует. Например:

приложение/просмотров/пользователей/preferences.html.erb

<% content_for :body_id, "my_preferences" %>

Ответ 2

Первое, что я сделал бы, было бы следующим:

#index.html.erb
<%= render @beasts %>

#_beast.html.erb
<%= beast.body %>
<%= link_to_next_beast_action(beast) %>    

#beast_helper.rb
def link_to_next_beast_action(beast)
  if beast.dead?
    link_to "bury", bury_beast_path( :id => beast.id ) 
  else
    link_to "kill!", kill_beast_path( :id => beast.id )
  end
end

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

Затем я переместил логику, чтобы показать ссылки убить/похоронить в помощника зверя. Таким образом, если вы решите добавить другое действие (например, "вернуть из мертвых" ), вам нужно будет только изменить своего помощника.

Помогает ли это?

Ответ 3

Третий вариант заключается в использовании модели представления из "Ячейки ячеек" . Это очень популярная структура, которая привносит объектную ориентацию в слой вида в Rails.

# app/cells/beast/cell.rb

class Beast::Cell < Cell::Concept
  def show
    return dead if model.dead?
    kill
  end

private
  def dead
    link_to "bury", bury_beast_path( :id => model.id ) 
    # you could render a view here, too!
  end

  def kill
    link_to "kill!", kill_beast_path( :id => model.id )
  end
end

Затем вы создаете модель представления с помощью помощника (в представлении или контроллере).

# app/views/beasts/index.erb

<%= concept(:beast, @beast).call %>
<%-# this returns the link content %>

Это все! Вы можете проверить эту ячейку, изолированную в отдельном тесте. Ячейки также дают вам представление рендеринга, просмотр наследования и многое другое.

В качестве примера вы можете использовать представление для ссылки kill.

# app/cells/beast/cell.rb

class Beast::Cell < Cell::Concept

  # ..

  def kill
    render :kill
  end
end

Это отображает вид убийцы ячейки.

# app/cells/beast/views/index.erb

<%= link_to "kill!", kill_beast_path( :id => model.id ) %>

Обратите внимание на расположение представления, оно прекрасно упаковано в каталог соты.

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

Ответ 4

Другим старшим будет не использовать шаблоны и помощники вообще. Для рендеринга вы можете:

  • визуализировать ваши представления непосредственно с ваших контроллеров с помощью render (: inline = > ). Если вы по-прежнему хотите, чтобы форматы Views и Controls были отделены, вы можете создавать модули /mixins, которые вы включаете в контроллеры.
  • или создайте свои собственные классы просмотров и используйте их для отображения вашего ответа.

Идея заключается в том, что помощники и система шаблонов erb tempating не используют ООП, так что в конце дня вы не можете определить общие типы поведения, которые вы будете специализировать в соответствии с потребностями каждого контроллера/запроса; чаще, чем не один, заканчивается переписывание очень похожих выглядящих кусков кода, что не очень хорошо с точки зрения обслуживания.

Затем, если вам все еще нужны вспомогательные методы (например, form_tag, h, raw,...), вам нужно включить их только в класс контроллера/выделенного класса.

Смотрите это: rails-misapprehensions-helpers-are-shit для веселой, но полезной статьи.

EDIT: чтобы не звучать как полный душ, я бы сказал, что реализация этого зависит от того, насколько велика ваша заявка, и как часто вам придется обновлять свой код. Кроме того, если вы делегируете проект не-программисту, он/она вполне может участвовать в некоторых курсах программирования, прежде чем вникать в ваш код, что, по общему признанию, будет менее понятным, чем с синтаксисом шаблонов.