Рендеринг трех разных частей в зависимости от нажатия кнопки

Итак, у меня есть такой макет:

главная / index.html.erb:

<div class="optionscontainer btn-group btn-group-justified">
   <%= link_to posts_path, class:"options btn btn-primary", remote: true do %>
      <i class="fa fa-book optionseach" aria-hidden="true"></i>All posts
   <% end %>
   <%= link_to stories_path, class:"options btn btn-primary", remote: true do %>
      <i class="fa fa-book optionseach" aria-hidden="true"></i>All stories
   <% end %>
</div>
   <div id="content" class="">
   </div>

В posts_controller.rb

Я имею:

def index
    @posts = Post.all
    respond_to do |format|
      format.html #looks for views/books/index.html.erb
      format.js   #looks for views/books/index.js.erb
    end
  end

В историях_контроллер.рб

Я имею:

def index
    @stories = Story.all
    respond_to do |format|
      format.html #looks for views/books/index.html.erb
      format.js   #looks for views/books/index.js.erb
    end
  end

По моему мнению / posts / index.js.erb

$("#content").html("<%= j (render 'posts') %>");

На мой взгляд / story / index.js.erb

$("#content").html("<%= j (render 'stories') %>");

И у меня также есть_posts.html.erb вviews/posts а также_stories_html.erb вviews/stories

Что происходит, когда я нажимаю на кнопку сообщений, я отображаю представление, но когда я нажимаю на кнопку историй, ничего не отображается?

 yogodoshi10 авг. 2016 г., 16:02
Как вы хотите сделать их? Как запрос AJAX? Вы знаете, как создать действие на контроллере?
 Gurmukh Singh10 авг. 2016 г., 16:06
Я новичок в рельсах и веб-разработке. Если AJAX - лучший способ, пожалуйста, покажите пример

Ответы на вопрос(3)

должны передать дополнительную информацию со ссылкой как

<div style="margin-top:50px;" class="wrapper">
  <div class="optionscontainer btn-group btn-group-justified">
    <a style="background-color:#4183D7;" href="<%= path_to_index_home(request: :p) %>" class="options btn btn-primary" data-remote=true><i class="fa fa-book optionseach" aria-hidden="true"></i>All posts</a>
    <a style="background-color:#59ABE3;" href="<%= path_to_index_home(request: :s) %>" class="options btn btn-primary" data-remote=true><i class="fa fa-rss optionseach" aria-hidden="true"></i>all stories</a>
    <a style="background-color:#81CFE0;" href="<%= path_to_index_home(request: :b) %>" class="options btn btn-primary" data-remote=true><i class="fa fa-users optionseach" aria-hidden="true"></i>all books</a>
  </div>
  <div data-load-partial>
    <%= render 'name_of_your_default_partial' , locals: {collection: @collection} %>
  </div>
</div>

Теперь мы должны отредактировать наш контроллер. Добавьте эту строку в верхней части вашего контроллера

ALLOWED_REQUESTS = { p: 'Post' , s: 'Story' , b: 'Book' }

Отредактируйте свое домашнее действие как

@request = params[:request].blank? ? 'Post' : ALLOWED_REQUEST[params[:request].to_sym]
@collection = @request.constantize.all

Теперь пришло время сделать соответствующее частичное. Если у вас разная структура таблицы и вы хотите отображать разные поля с разным html, вы можете создать три разных партиала как _book.html.erb, _story.html.erb, _post.html.erb, и вы можете вызывать их как дома файл .js.erb

$('[data-load-partial]').html('<%= j render partial: "#{@request.downcase}" , locals: { collection: @collection } %>');

Если вы хотите использовать одно и то же частичное для трех типов, вы можете сделать это как

$('[data-load-partial]').html('<%= j render partial: "name_of_your_partial" , locals: { collection: @collection } %>');
Решение Вопроса

Хорошо, прежде чем перейти к решению, давайте разберемсяrequest-response цикл.

Когда вы ищетеhttp://stackoverflow.comчто происходит, вы отправляете запрос отclient(ваш браузер) в StackOverflow (SO)server, Клиент и сервер общаются черезHTTP протокол и, если пользователь запрашивает что-то, что сервер знает, он обслуживает (отправляет) ответ (html, css, js файлы). Браузер знает, как отображать HTML-контент, полученный с сервера. Каждый браузер имеет свою собственную таблицу стилей (user-agent-stylesheet), а также применяет стили в файлах css, связанных на html-странице, отправленной с сервера. Обратите внимание, что все это происходитсинхронно и покаserver обрабатывает запрос клиента, вкладка браузераinactive как ожидание ответа сервера. Тот же процесс происходит, когда вы нажимаете на ссылку. Создает новый запрос к серверу.

Ответ с сервера может бытьHTML, JSON, XML и т.д. Как вы могли заметить,synchronous общение - это не то, чего мы всегда хотим.

Если мы сделаем новыйsynchronous запрос, браузер получаетHTML, CSS а такжеJS а такжеimage файлы заново (не давайте в кеширование). И мы не хотим обновлять всю страницу для каждого запроса.

Зачастую только части страницы обновляются после запроса, и это обеспечивает хороший пользовательский опыт.

Это где Javascript хорош в. Он может делать запросы к серверу асинхронно (веб-страница не перезагружается), а также обновлять части страницы, используя что-то под названиемAJAX(Асинхронный Javascript XML).

Типичный запрос AJAX выглядит следующим образом. Вы делаете запрос к серверу, но на этот раз асинхронно, и сервер отвечаетXML скорее, чемHTML а такжеJavascript разбираетXML документ обновляет часть страницы. Несмотря на то, что в настоящее время он называется AJAX, в настоящее время JSON используется для обмена информацией между службами.

Итак, чтобы сделать AJAX-запрос, нам нужна ссылка, которая при нажатии отправляетXMLHttpRequest(асинхронный запрос) и сервер должен ответитьJSON или жеXML или, а затем сценарий должен проанализировать ответ и обновитьDOM(Объектная модель документа). Выполнение запроса AJAX вVanilla JS(простой javascript) сложен, и люди обычно используютJquery«sajax метод для выдачи AJAX-запроса (меньше строк кода). Увидетьhttp://api.jquery.com/jquery.ajax/ для дополнительной информации.

Но вrails, это даже проще. Мы можем сделать запрос AJAX, используяUJS(Ненавязчивый Javascript). Давайте посмотрим на это в действии.

Чтобы сделать ссылку, отправьте запрос AJAX, вам нужно установитьremote: trueвlink_to помощник. Это добавляетdata-remote=trueв сгенерированном HTML.

Например, следующий эрб

<%= link_to "All books", books_path, remote: true %>

генерирует HTML

<a data-remote="true" href="/books">All books</a>

Хорошо. Теперь мы готовы сделатьAJAX запрос. Измените свой код как

<div style="margin-top:50px;" class="wrapper">
  <div class="optionscontainer btn-group btn-group-justified">

    <%= link_to posts_path, class:"options btn btn-primary", remote: true do %>
      <i class="fa fa-book optionseach" aria-hidden="true"></i>All posts
    <% end %>


   <%= link_to stories_path, class:"options btn btn-primary", remote: true do %>
      <i class="fa fa-rss optionseach" aria-hidden="true"></i>All stories
    <% end %>

   <%= link_to books_path, class:"options btn btn-primary", remote: true do %>
      <i class="fa fa-users optionseach" aria-hidden="true"></i>All books
    <% end %>
</div>

<div id="content">
  <!-- The content goes here -->
</div>

Я предполагаю, что у вас есть контроллеры, модели и настройки представлений. Также выполнитьrake routes в терминале, чтобы увидеть существующие маршруты вашего приложения. Вы должны увидеть следующее (порядок не важен)

Prefix  Verb   URI Pattern                Controller#Action
posts   GET    /posts(.:format)            posts#index
stories GET    /stories(.:format)          stories#index
books   GET    /books(.:format)            books#index

Замечания:format здесь соответствует возвращаемому формату, который может бытьhtml, js, xml или жеjson.

posts_path в одном изurl_helper что указывает наposts#index, то есть всякий раз, когда запрос сделан на сервер вrails приложение, оно сначала достигает маршрутизатора и отправляется в соответствующийcontroller действие, указанное вroutes.rb

В этом случае, если мы сделаем запросhttp://localhost:3000/booksзапрос отправляется в действие books # index. В действии вы можете получить данные изdatabase и отправьте ответ клиенту.

Так как мы заинтересованы в AJAX и мы определилиremote:trueРельсы будут ожидатьJS ответ должен быть возвращен клиенту (т.е.script который отвечает за динамическое отображение контента).

Я объясню, как обращаться с запросом AJAX дляBooksController и вы можете применить ту же идею для других контроллеров. (posts а такжеstories).

class BooksController < ApplicationController

  def index
    @books = Book.all

    respond_to do |format|
      format.html #looks for views/books/index.html.erb
      format.js   #looks for views/books/index.js.erb
    end

  end

  #other actions
end

Все, что мы здесь делаем, это говорим контролеру о рендеринге.index.js.erb если клиент запрашивает ответ JS или сделатьindex.html.erb в случае ответа HTML. Как рельсы знают, чтобы сделатьindex.html.erb или жеindex.js.erb когда мы не указали файл для рендеринга? Вот для чего популярны рельсы.Соглашение по конфигурации.

На самом деле,controller выводит шаблон для рендеринга изaction название.

Следующим шагом является использование@books обновить#content дела. Прежде чем добавить код для рендеринга всех книг, нам нужен шаблон для рендеринга, верно? Вот где входят частичные. Частичное является многоразовымview' and a partial in rails is prefixed with '_'. For example:_books.html.erbis a partial forbooks`.

Создать частичныйapp/views/books/_books.html.erb

<% @books.each do |book| %>
  <div class="book">
    #Display the fields
  </div>
<% end %>

Теперь создайтеapp/views/books/index.js.erb и добавьте следующее:

$("#content").html("<%= j (render 'books') %>");

Этот однострочник будет оказывать частичное_books.html.erb в#content дела. Подождите. Как это работает? Давайте разбить его на куски.

Что-нибудь внутри<%= %> это рубиновый код Его исполняется и значение заменяется вместо<%= %>,erb шаблонный англ позволяет писатьruby код внутриjavascript, Итак, что это делает?

<%= j (render 'books') %>

Это сделаетbooks/_books.html.erbвыводится из параметра вrender, Возвращает HTML, сгенерированный_books.html.erb.

Что значитj делать? Это на самом деле псевдонимescape_javascript метод. Он используется для экранирования содержимого, возвращенного из частичного_books.html.erb.

Объясняя причинуescaping HTML сделает этот ответ еще дольше. Я настоятельно рекомендую вам прочитать ответ Кикито (3-й) вэтот ТАК нить.

Итак, мы передаем html из частичного в виде строки (обратите внимание на кавычки вокруг<%= %>) чтобыhtml метод, который добавляется внутри#content дела. Это оно!

Я рекомендую вам проверить журналы сервера и изучитьNetwork вкладка в инструментах разработчика, чтобы получить глубокое понимание того, как работает AJAX.

Сделайте то же самое для других контроллеров (PostsController а такжеStoriesController).

Надеюсь это поможет.

 Arun Kumar Mohan17 авг. 2016 г., 23:08
@GurmukhSingh, рад, что это работает!
 Gurmukh Singh17 авг. 2016 г., 22:36
@AunKumar это работает нормально, это была маленькая ошибка на моей стороне! Спасибо за помощь, человек!
 Arun Kumar Mohan17 авг. 2016 г., 22:26
 Gurmukh Singh15 авг. 2016 г., 09:18
Когда я сталкиваюсь с небольшой проблемой, у меня есть представления для книги, сообщений и т. Д., Но эти кнопки находятся на главной странице index # и используют другой контроллер, называемый index и method home. Я обновил свой вопрос.
 Gurmukh Singh17 авг. 2016 г., 09:57
так что в основном я пытаюсь сделать вид в отдельном виде. Почта и книги и отдельные леса, так что у них есть свои взгляды. Я работаю в другом контроллере с именем index, поэтому я применяю приведенную выше логику к контроллеру индекса, где я создаю файл .js для индекса app / views / index / home.js.erb и затем помещаю $ ("# content") .html ("<% = j (render 'books')%>"); в нем, а затем для постов я делаю то же самое $ ("# content"). html ("<% = j (render 'posts')%>"); который идет в том же home.js.erb. Я надеюсь, что это делает сцены: Это тогда не работает?
 Arun Kumar Mohan17 авг. 2016 г., 22:01
@GurmukhSingh, вы говорите, что это работает дляposts но не дляstories? Вы изменили свойStoriesController#index оказыватьjs ответ? Если это нормально, после нажатия кнопки истории, пожалуйста, проверьтеnetwork вкладку в ваших инструментах разработки и посмотреть журналы сервера, чтобы увидеть, что происходит. Разместите журнал и позвольте мне попытаться решить проблему.
 Arun Kumar Mohan17 авг. 2016 г., 10:04
@GurmukhSingh Почему вы хотите иметь все сценарии вindex/home.js.erb? Если вы действительно хотите сделать это таким образом, тогда есть проблема. В ссылках вам нужно передать дополнительную информацию о том, какая кнопка была нажата, и не только об этом, вам нужны условия в вашемindex.js.erb сделать конкретный фрагмент, который делает его слишком сложным. С моим решением вы перенаправляете запрос на другой контроллер, который избегает условных выражений и, следовательно, уменьшает объем кода. Имеет смысл?
 Gurmukh Singh17 авг. 2016 г., 22:22
да, это работает для сообщений, но не для историй, что я ищу на вкладке сети
 Gurmukh Singh17 авг. 2016 г., 21:52
Я отредактировал свой вопрос, показывая, как я реализовал ваше решение, но оно не работает идеально
 Arun Kumar Mohan17 авг. 2016 г., 06:16
@GurmukhSingh Я тебя не понимаю. В индексе # home view есть три ссылки, где каждая из них отправляет запрос на разные контроллеры. В моем ответе вы можете найти ссылки, указывающие наstories_path, books_path а такжеposts_path, В своем ответе я написал шаги, которые необходимо сделать дляbooks_controller так что ссылка дляbooks_path оказываетjs ответ. Вы можете повторить те же шаги (данные разные для каждого) для других контроллеров. Если это не то, что вы хотите, пожалуйста, прокомментируйте желаемое поведение.

Ссылки должны быть установлены наremote: true и им придется указывать на разные действия (или на одни и те же, но получать разные параметры).

И эти действия должны будут реагировать на js и отображать его js.

Это было бы что-то вроде этого:

Ваш взгляд:

<div style="margin-top:50px;" class="wrapper">
  <div class="optionscontainer btn-group btn-group-justified">
    <%= link_to 'All Posts', posts_path, class: 'options btn btn-primary', method: :get, remote: true %>
  </div>
  <div id='placeholder'>
    <%= render 'all_posts' %>
  </div>
</div>

просмотров / сообщений / index.js.erb

$('#placeholder').html("<%= j (render 'all_posts') %>");

Ваш ответ на вопрос