I have a rails 4 project that has some public routes (home, contact, about) and then some routes that are only for logged in users that are name spaced under admin (admin/home, admin/contact, admin/about). The admin routes basically edit and update what is displayed in the public routes.
I have an admin layout for the admin routes and a application layout which does the normal public routes. My admin layout has to have data-no-turbolink in the body because I NEED to disable turbolinks in order for the CKEditor gem to work properly.
Each layout has a link that shows up if a User is logged in. So if a user is logged in and visits "localhost:3000/" or "http://localhost:3000/contact" etc, there will be a link that will link to the admin page.
Likewise if a logged in user visits "http://localhost:3000/admin/home" or "http://localhost:3000/admin/contact" there will be a link that links to the public page. Here is what the layouts look like.
ADMIN LAYOUT
<!DOCTYPE html>
<html>
<head>
<title>TITLE</title>
<script src="//cdn.ckeditor.com/4.4.6/basic/ckeditor.js"></script>
<%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track' => false %>
<%= javascript_include_tag 'application', 'data-turbolinks-track' => false %>
<%= csrf_meta_tags %>
</head>
<body data-no-turbolink>
<div class="page-wrap">
<header id="main-head">
<%= render "nav"%>
</header>
<% if logged_in %>
<div id="review-default"><%= link_to "Preview Pages As A Regular User.", root_path %></div>
<% end %>
<%= yield %>
</div>
</body>
</html>
APPLICATION LAYOUT
<!DOCTYPE html>
<html>
<head>
<title>TITLE</title>
<script src="//cdn.ckeditor.com/4.4.6/basic/ckeditor.js"></script>
<%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track' => true %>
<%= javascript_include_tag 'application', 'data-turbolinks-track' => true %>
<%= csrf_meta_tags %>
</head>
<body>
<div class="page-wrap">
<header id="main-head">
<%= render "nav"%>
</header>
<% if logged_in %>
<div id="review-admin"><%= link_to "Return to Admin Panel.", admin_home_path %></div>
<% end %>
<%= yield %>
</div>
</body>
</html>
My problem is that when I click from say the root path "/" to "admin/home" the forms that CKEditor is applied to dont display properly until I refresh the page, which leads me to think that they are not displaying properly because turbo links are not disabled.
But when I, for example, log in and get directed to the adminroutes they are disabled. But they dont seem to be when I am linked to them from the links in the layout...
I hope that makes sense.
What am i doing wrong and how do I stop turbo links from being applied to my admin routes?
EDIT
my solution was to add
<% if logged_in %>
<body data-no-turbolink>
<% else %>
<body >
<% end %>
to both my admin and application layouts. This solves my problem, but if anyone has a more elegant solution (since if the admin layout is being called correctly by having layout "admin" in my admin controller it doesn't seem like I would have to do this), I am all ears!
BTW, I love you StackOverFlow. Thank you for all your patience and help.
my solution was to add
<% if logged_in %>
<body data-no-turbolink>
<% else %>
<body >
<% end %>
to both my admin and application layouts. This solves my problem, but if anyone has a more elegant solution (since if the admin layout is being called correctly by having layout "admin" in my admin controller it doesn't seem like I would have to do this), I am all ears!
Related
I'm trying rails/turbolinks 3, and want to make partial replacement work, but no luck with that. Here is code:
gemfile
gem 'turbolinks', github: 'rails/turbolinks' (shows using 3.0.0 so problem not in that, turbolinks included in app..n.js).
router:
root 'home#index'
get '/partial1' => 'home#partial1', as: 'partial1'
get '/partial2' => 'home#partial2', as: 'partial2'
controller
class HomeController < ApplicationController
def index
end
def partial1
render change: 'partial1'
end
def partial2
render change: 'partial2'
end
end
layouts/application.html.erb
<!DOCTYPE html>
<html>
<head>
<title>Turbo</title>
<%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track' => true %>
<%= javascript_include_tag 'application', 'data-turbolinks-track' => true %>
<%= csrf_meta_tags %>
</head>
<body>
<div>
this is home
<%= link_to("partial asd1", partial1_path) %>
<%= link_to "partial 2", partial2_path%>
</div>
<div id="partial1" data-turbolinks-temporary>
<p>her</p>
</div>
<div id="partial2">
<p>here is partial</p>
</div>
<%= yield %>
</body>
</html>
But it doesn't replace those partials, it works just as regular. I also tried to put turbolinks: true and it renders Turbolinks.replace('some html', {change: ['partial1']}), but also nothing happens. I also tried e.preventDefault and Turbolinks.visit('/partial1', {change: 'partial1'}), and it also not working as well as calling Turbolinks.replace('some html', {change: 'partial1'}). Turbolinks js loads in browser all right. And in dev it shows calling Turbolinks.visit. Tried on different machines.
If anyone made it work please tell me how you did it.
How would I display different versions of headers in Rails in my application.html.erb view? For instance, for my landing page, I have a pretty big header that includes a callout and some sign-up and sign-in buttons. For other static pages, I have a normal small header with a logo and a few links to the right. And for my dashboard when users log in, it will look a little different as well.
How can I display certain headers in an if/else statement where Rails will output the different versions of headers based on the current url or view in my application.html.erb?
To answer your question with an example this is what you may want to do.
Rails has a provision to use nested view templates using the content_for and yield tags.
Do the following thing to achieve what you want -
In app/views/layouts/application.html.erb - Add a ternary expression which acts as a if else. While rendering the views rails will look for a <% content_for :custom_header do %> in the view templates. If it doesn't find that it will render the partial app/views/layouts/_default_header.html.erb instead.
<html>
<head>
<title><%= #page_title or "Page Title" %></title>
<%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track' => true %>
<%= javascript_include_tag 'application', 'data-turbolinks-track' => true %>
<%= csrf_meta_tags %>
</head>
<body>
<!-- Code to conditionally load a header -->
<%= content_for?(:custom_header) ? yield(:custom_header) : render :partial => "layouts/default_header" %></div>
<!-- For the body -->
<%= yield %>
</body>
</html>
Now since you say that most pages will have a static small header, save the html code for that in a partial under app/views/layouts/_default_header.html.erb.
In you landing page (for example the the view app/views/welcome/index.html.erb) you can use the content_for tag with the identifier :custom_header that we have used in the application.html.erb
Add the following in your landing page.
<% content_for :custom_header do %>
<div class="custom-header">
<!-- Your complex header with sign in and signup links... -->
</div>
<% end %>
The ternary operator in the application.html.erb will pick up this content from the content_for tag in the landing page and insert the content in place of the yield(:custom_header).
Hope this helps.
It sounds like you may want to use a nested layout.
I have a controller (not model related) which searches for stuff on YouTube via API. What I'm trying to achieve is simple enough...if someone clicks the search button when no string was entered then a flash notice will appear saying 'please enter search string'.
The 'main' view is as follows:
<%= form_tag({:controller => 'main', :action => 'index'}, :method => 'get') do %>
<%= label_tag(:text, 'Search:') %>
<%= text_field_tag(:text) %>
<%= submit_tag('Search') %>
<% end %>
<div id="flash">
<% if flash.now[:notice] %>
<p id="notice"><%= flash.now[:notice] %></p>
<% end %>
</div>
My index action in my 'main' controller looks like this:
def index
if params[:text].blank?
flash.now[:notice] = 'Please enter a search string'
render 'index'
else
#do searches on YouTube
end
I've looked at other question similar to this on stackoverflow as well and tried a few thing and still doesn't work. I've played around with using flash[] versus flash.now[] and still the notice message just sticks even when I first load the page. I might be missing something quite trivial here but I've spent a while figuring it out and still stuck. Anyway help would be appreciated.
UPDATE:
Ok, I have found an answer. I simply added the following in my form in the view:
<%= hidden_field_tag :searching, true %>
then i changed my controller to:
flash.now[:notice] = 'Please enter a search string' if params[:searching]
This worked fine. This is courtesy of the answer here:
How do I stop a flash error message from showing on page load until after button is clicked in ruby on rails?
FOLLOW UP QUESTION: in the link above, it suggested a cleaner answer which is to use:
params[:search].blank? && !params[:search].nil?
However, this doesn't work for me. I get the error:
undefined method `gsub' for nil:NilClass
I'm a newbie in Ruby so is this a syntactical error?
This may help, worth a try. In my case, my flash message was not shown because I was using
flash.now[:notice]
When changed to
flash[:notice]
started showing it.
Full code, controller:
def create
user_data = user_params
user_data[:password] = SecureRandom.uuid
#user = User.new(user_data)
#user.save
flash[:notice] = 'An email was sent for the user to confirm their account.'
respond_with(#user)
end
aaplication.html.erb
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title><%= full_title(yield(:title)) %></title>
<%= csrf_meta_tags %>
<%= csp_meta_tag %>
<%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
<%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %>
<%= render 'layouts/shim' %>
</head>
<body>
<%= render 'layouts/header' %>
<div class="container">
<% flash.each do |message_type, message| %>
<div id=<%= message_type %> class="alert"><%= message %></div>
<% end %>
<%= yield %>
<%= render 'layouts/footer' %>
</div>
</body>
</html>
I'm trying to add a layout to the application layout. I having trouble trying to figure out all the different layout solutions. First I tried just a layout inside a layout because I didn't fully grasp what partials are or if they are layouts also? Maybe I can start with that question. What is the difference between a layout and a partial.
Here is what I have right now. I'm trying to just separate out my header code which has a navigation and some other elements into a separate layout. I want this layout to be on all views. Meaning it should be a layout inside the applications layout along with other views that are been called when their controllers are called. Which is covered in my code with the <%= yield %>. That yeild works but the :header one does not.
Application Layout app/views/layouts/application.html.erb
<!DOCTYPE html>
<html>
<head>
<title>home</title>
<%= stylesheet_link_tag "application", :media => "all" %>
<%= javascript_include_tag "application" %>
<%= csrf_meta_tags %>
</head>
<body>
<div id="header"><%= yield(:header) %></div>
<%= yield %>
</body>
</html>
Header layout app/views/layouts/application.html.erb
<% content_for :header %>
<p>HEADER TEXT</p>
<% end %>
Why would the code above not work?
I also saw code like this that I tried but it gave me an error.
<%= render layouts/header %>
Can someone please explain all these different methods.
Thanks.
It's good practice to separate your header and footer into partials which you would live in the views/layouts folder as '_header.html.erb' and '_footer.html.erb' respectively.
You can then optionally wrap each partial with specific div's which is what you're trying to do with the header (you could do the same with the body too), and it would end up looking like this:
<!DOCTYPE html>
<html>
<head>
<title>home</title>
<%= stylesheet_link_tag "application", :media => "all" %>
<%= javascript_include_tag "application" %>
<%= csrf_meta_tags %>
</head>
<body>
<div id="header">
<%= render 'layouts/header' %>
</div>
<%= yield %>
<div id="footer">
<%= render 'layouts/footer' %>
</div>
</body>
</html>
That will do what you want it to do.
Note that 'layouts/header' and 'layouts/footer' have '' around them.
To answer your question on what is the difference between a layout and a partial, well a layout is something that will used throughout your application, such as a consistent header or footer. A partial can be a layout, but it doesn't have to be, so you can partial specific to other views across your site.
<% content_for :header do %>
<p>HEADER TEXT</p>
<% end %>
You forgot the do
So - first - The yield syntax may or may not be correct, but I've never seen it, and I don't like it. I only ever call yield once in a file.
If you want to render a header in your application template file, that's certainly possible - my advice would be to place it in your template file directly - after all, that's what template files are for. If you want to completely encapsulate your header for some reason or another in seperate files, what you need is partials. You're going to do something like this:
<body>
<%= render :partial => "shared/header" %>
<%= yield %>
</body>
Which will render your header content, stored in /shared/_header.html.erb into the layout here.
Check out this guide here for more info
Ok so I have a problem with rails and rendering partials. I have a layout called profile and inside of the profile layout I have all my js, stylesheets, etc included.
<html>
<head>
<title>Profile</title>
<%= javascript_include_tag "https://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js" %>
<%= javascript_include_tag "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.10/jquery-ui.min.js" %>
<%= javascript_include_tag "application" %>
<%= stylesheet_link_tag "main" %>
<%= stylesheet_link_tag "reset" %>
<%= csrf_meta_tag %>
</head>
<body>
<%= yield %>
</body>
</html>
Inside of the yield tag(profile/index.html.erb) above is the following
<%= render :partial => 'pages/page', :layout => "layouts/default", :locals => {:page => #page } %>
Now in the pages/page view there are the same default tags such as css and js files. When i remove the css styles then I lose the styling for the pages/page view. Is there a way I can render a partial without recalling the same css and js files or what is a better way to go about doing something like so?
I always create the option to overwrite the stylesheets as follows:
<%= stylesheet_link_tag content_for?(:stylesheets) ? yield(:stylesheets) : "application", :debug => Rails.env.development? %>
Then inside a view
<% content_for :stylesheets %> some stuff or nothing in here <% end %>
That will let you specify in a view rendered in a layout you want no stylesheets and the same principle applies for javascripts.
That having been said if you are rendering a partial inside a layout that has an html tag and head etc. you should probably investigate if there is a better way to do what you are doing.
You need to pick one or the other: layout the original method call, or pass a layout to the partials. Doing both would be illogical.
There is a more thorough discussion here:
http://www.mikemayo.org/2012/rendering-a-collection-of-partials-with-content_for
I rarely see the usage of( or I am wondering if Rails support this usage... )
<!-- confirmed, this usage will cause error in Rails 3.2 -->
<%= render :partial => "some_partial", :layout => "some_layout" ... %>
I prefer to choose the specific layout in the controller:
def some_action
# some code
render :layout => "some_layout"
end
A partial is basically just a "slice of page" (like slice of cake... but in code form). It's designed to populate a small part of the page; typically one which will by dynamically updated depending on page variables.
Seems like you're confusing the purpose of layouts, views & partials in my opinion. If you want to dynamically load CSS / JS, put a "content_for" block in the profile views with a default layout, like this:
Layout
#layouts/default.rb
<html>
<head>
<title>Site Title</title>
<%= javascript_include_tag "https://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js" %>
<%= javascript_include_tag "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.10/jquery-ui.min.js" %>
<%= javascript_include_tag "application" %>
<%= stylesheet_link_tag "main" %>
<%= stylesheet_link_tag "reset" %>
<%= yield :header_includes %>
<%= csrf_meta_tag %>
</head>
<body>
<%= yield %>
</body>
</html>
Views
#views/profiles/index.html.erb
<% content_for :header_includes do %>
<%= stylesheet "profile_custom_css" %>
<% end %>
Partial
Partials could be used to keep your code DRY & give the output of specific header files, like this:
Partial
#views/elements/_custom_header.rb
<% content_for :header_includes do %>
<% headers.each do |type, value| %>
<% if type == "java" %>
<%= javascript_include_tag value %>
<% else %>
<%= stylesheet_link_tag value %>
<% end %>
<% end %>
<% end %>
View
#views/profiles/index.html.erb
<%= render :partial => 'elements/custom_header', locals: { :headers => [["java", "profile_custom"], ["stylsheeet", "profile_custom"]] } %>
#Resume standard view code here
Layout
#layouts/default.rb
<html>
<head>
<title>Site Title</title>
<%= javascript_include_tag "https://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js" %>
<%= javascript_include_tag "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.10/jquery-ui.min.js" %>
<%= javascript_include_tag "application" %>
<%= stylesheet_link_tag "main" %>
<%= stylesheet_link_tag "reset" %>
<%= yield :header_includes %>
<%= csrf_meta_tag %>
</head>
<body>
<%= yield %>
</body>
</html>
I've not tested passing the partial locals as a hash, so the syntax may be incorrect, but this is what we'd do to load up the required code. The added benefit is that content_for only yields content that has been defined (I.E you just have to include yield :custom_headers and it will only show if the content block is present)