简体   繁体   中英

How to render another page (Controller Action + View) inside current view

Let's say I have a UserProfileController#show which renders a user's profile account page. The associated views and partials for this controller are under /app/views/user_profile/*

As with any UserProfile page, the user should be able to edit their preferences. This is done by clicking a preferences link which triggers the UserPreferences#show and it displays a whole new page by rendering the views under /app/views/user_preferences/*

My current issue is that the latter page is a whole separate page that I have to link to. I'd love to instead be able to bring up the preferences page in a modal without leaving the user profile page. Or maybe I just want it embedded in the profile page itself at the bottom (ie it doesn't have to necessarily be a popup modal - wasn't looking for a specific answer to that).

The issue is that I have no way to call a whole new controller and action from my current UserProfileController view. Is there a way to call this new route and have it generate the whole new page within my current page?

The only answer I've received so far is that I should consider doing it all from the same controller, but that's really overloading the UserProfileController and my action method is becoming long and messy.

Thanks!

You're thinking about it wrong; you're not dealing with "pages" but controller actions and views . Subtle but important difference:

在此处输入图片说明

Rails itself is an MVC ( M odel V iew C ontroller) framework. It's not unique in this sense, but since many Rails devs don't have experience elsewhere, they have to learn the "mindset" of MVC first hand.

As you can see above, you can't simply render a "page" and see all the data you need. You need to populate the view with data (done in the controller), allowing Rails to send the relevant HTML etc in the browser.

Thus, you have to ask yourself how you're going to:

  1. Populate the data for your user_preferences view
  2. Render that view in the browser

Partials

The feature you'll probably need is partials .

Partials allow you to call a "sub view" in a main view. You have to provide the data for it etc, but it means you can render things such as menus and profiles inside other views, reusing the same code each time ( DRY - Don't Repeat Yourself ).

Partials are simple to create - just prepend an underscore to their name:

#app/views/user_preferences/_menu.html.erb
This is a user preferences partial.
You can call this in any view but make sure you have the correct data supplied!

Now, the important part is in how you invoke this partial:

#app/views/user_profile/index.html.erb
<%= render "user_preferences/menu", locals: {user: @user} %>

You'll be able to populate the @user variable inside the Users controller:

#app/views/user_profiles_controller.rb
class UserProfilesController < ActionController::Base
   def index
      @user = User.find x
   end
end

--

Ajax

The alternative is to use Ajax and download the entire user_preferences view on demand. I would not recommend this for this instance.

Ajax basically sends an asynchronous (parallel) request to the server from your browser. The response received is then appended to the page. It's used to provide snippets of functionality (loading user data etc).

Ajax uses Javascript, and would have to be done like this:

#app/assets/javascripts/application.js
$(".some_button").on("click", function() {
    $.ajax({
        url: "path/to/user_preferences",
        success: function(data) { // do something here }
    });
});

As your question suggested you do have both the controller associated with user and on that page you can easily get user object.

So you should use your userprofile controller's show action to get information of userprofile only. And in show view you should have some div which trigger ajax call on page load like below:

#show.html.erb

.....your user profile html....
<div id="user_prefrences" data-id="#{@user.id}"></div>
.....your user profile html....

And following changes in you js file.

$(function(){
  var id = $('#user_prefrences').attr('data-id') ## get user id here
  $.ajax({
    url: '/user_prefrences/' + id, 
    success: function(result){
      $("#user_prefrences").html(result);
    }
  });
});

In your controller remember to check for ajax request and send data without layout.

## UserPrefrences Controller

def show
  if request.xhr?
    ....
    layout false
  else
  end
end

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM