Just like in title: What is the proper way to integrate SEO stuff like Facebook OpenGraph tags in apps that use rails backend API (installed with webpacker) with a framework like Vue?
This is how part of my config/routes.rb looks like:
namespace :api, defaults: { format: :json } do
namespace :v1 do
resources :posts, only: [:index, :show]
end
end
get '/', to: 'front#index', format: false
get '/*path', to: 'front#index', format: false
For now app is designed in the way, where all requests on front-end part are handled by vue-router.
My layouts/application.html looks almost, like on the attached snippet:
<html>
<head>
<%= javascript_pack_tag 'front' %>
<%= stylesheet_pack_tag 'front' %>
</head>
<body>
<div id="app">
<%= yield %>
</div>
</body>
</html>
My question is, what is the proper way to manage stuff like Facebook Open Graph when there is no straight forward access to <head> section?
I can't use fairly default rails stuff like content_for because everything happens inside script.
Or maybe am I wrong? Missing something fancy, important here?
It would be grateful to get any advice, thanks.
I am trying to build rails HTML emails, but the structure (header and footer) of the emails is duplicated in each one. Typically it's not a problem, but with the inline styles as well, it seems like it can be an issue if I want to change the color. How can I pull these elements out of each file and into one?
Also, is there anyway to eliminate the duplication of text between the html.erb and text.erb files.
A simple way to do it is to reference a couple of partials. Let's say they're named something like this:
_email_header.html.erb
_email_footer.html.erb
Then you can refer to them inside each of your emails:
<%= render :partial => 'email_header' %>
Blah, email-specific content here...
<%= render :partial => 'email_footer' %>
That will work, but will still lead to a bunch of copy-paste, albeit less than the original version with the full structure inlined. A cleaner way to manage this is to set up a custom layout for these emails.
The "Layout and Rendering" Rails Guide and the layouts section of the "Action Mailer" Rails Guide are helpful backgrounders for this, if you haven't done this before.
You will see from those references that there are multiple ways to invoke a layout within Action Mailer (and more ways still, outside of a mail context), but to take one example usage, you can create a layout template file here: app/views/layouts/{your_mailer_name}.html.erb. E.g., "user_mailer.html.erb"
Its contents could look something like this:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>My Fancy Email</title>
</head>
<body>
<%= render :partial => 'email_header' %>
<%= yield %>
<%= render :partial => 'email_footer' %>
</body>
</html>
Note the yield call, that's where your specific email content will render.
This approach keeps your content "DRY".
I'm trying to transition an application from 3.0.7 to 3.1. I've moved around the assets to the app/assets directory and I thought that I have everything configured correctly.
My problem is that the layout file won't correctly render partials and other layout files. If all I have inside my layout is <%= yield %> then it correctly renders the view files.
But if I try to render another layout file inside layouts/omega/application.html.erb like:
<%= render "layouts/omega/head" %>
<%= yield %>
Then it dumps the html onto the page with all of the elements and html tags included in the text:
<div id="top-pane"> <div class="center-content">.....
"Some text that was correctly displayed from the view file that was called through yield"
If I try to render another file, say in home/index.html.erb:
<p> this is home/index </p>
<%= render 'omega/test' %>
Then the output will be:
"this is home/index
<p> this is a test layout </p> "
Where again, the text from home/index is outputted correctly, but the rendered partial still includes the html elements. What's changed in 3.1 that's making this happen?
(By the way, I'm working inside a Rails Engine, which is why I have everything namespaced with omega)
I have only a single page that requires jquery ui in my entire application. How can conditionally include the javascript files in that single page?
I believe in Rails 2 I could use: (in application.html.erb)
<%- if controller.controller_name == "posts" && controller.controller_action == "new" -%>
<%= stylesheet_link_tag 'jquery-ui-1.8.13.custom.css' %>
<%= javascript_include_tag 'jquery-ui-1.8.13.custom.min.js', 'autocomplete-rails.js' %>
<%- end -%>
But controller.controller_action throws an undefined method error. And after looking at the API, it looks like it's been removed?
Maybe it would be best to remove the conditional from application.html.erb altogether and just put it at the top of posts/new.html.erb ?
I would avoid delegating responsibility for this to your application layout. If you don't need jQuery UI on more than a single view, you are best off letting the view handle that. The following let's you do just that while still keeping your output HTML clean and sensible (ie. not putting JS all over the place willy nilly).
In your layout (application.html.erb):
<head>
<title>Foo Bar</title>
<%= yield :page_specific_assets %>
</head>
In your view that requires jQuery UI (posts/new.html.erb):
<% content_for :page_specific_assets do %>
<%= stylesheet_link_tag 'jquery-ui-1.8.13.custom.css' %>
<%= javascript_include_tag 'jquery-ui-1.8.13.custom.min.js', 'autocomplete-rails.js' %>
<% end %>
Note: despite convention, putting unnecessary javascript in the <head> degrades performance.
I believe it's:
controller.action_name
Whats the proper way to set the page title in rails 3. Currently I'm doing the following:
app/views/layouts/application.html:
<head>
<title><%= render_title %></title>
<%= csrf_meta_tag %>
app/helpers/application_helper.rb:
def render_title
return #title if defined?(#title)
"Generic Page Title"
end
app/controllers/some_controller.rb:
def show
#title = "some custom page title"
end
Is there another/better way of doing the above?
you could a simple helper:
def title(page_title)
content_for :title, page_title.to_s
end
use it in your layout:
<title><%= yield(:title) %></title>
then call it from your templates:
<% title "Your custom title" %>
There's no need to create any extra function/helper. You should have a look to the documentation.
In the application layout
<% if content_for?(:title) %>
<%= content_for(:title) %>
<% else %>
<title>Default title</title>
<% end %>
In the specific layout
<% content_for :title do %>
<title>Custom title</title>
<% end %>
I found that apeacox's solution didn't work for me (in Rails 3.0.3).
Instead I did...
In application_helper.rb:
def title(page_title, options={})
content_for(:title, page_title.to_s)
return content_tag(:h1, page_title, options)
end
In the layout:
<title><%= content_for(:title) %></title>
In the view:
<% title "Page Title Only" %>
OR:
<%= title "Page Title and Heading Too" %>
Note, this also allows us to check for the presence of a title and set a default title in cases where the view hasn't specified one.
In the layout we can do something like:
<title><%= content_for?(:title) ? content_for(:title) : 'This is a default title' %></title>
This is my preferred way of doing it:
application_helper.rb
module ApplicationHelper
def title(*parts)
content_for(:title) { (parts << t(:site_name)).join(' - ') } unless parts.empty?
end
end
views/layouts/application.html.erb
<title>
<%= content_for?(:title) ? yield(:title) : t(:site_name) %>
</title>
config/locales/en.yml
en:
site_name: "My Website"
This has the nice advantage to always falling back to the site name in your locales, which can be translated on a per-language basis.
Then, on every other page (eg. on the About page) you can simply put:
views/home/about.html.erb
<% title 'About' %>
The resulting title for that page will be:
About - My Website
Simples :)
#akfalcon - I use a similar strategy, but without the helper.. I just set the default #title in the application controller and then use, <%=#title%> in my layout. If I want to override the title, I set it again in the controller action as you do. No magic involved, but it works just fine. I do the same for the meta description & keywords.
I am actually thinking about moving it to the database so an admin could change the titles,etc without having to update the Rails code. You could create a PageTitle model with content, action, and controller. Then create a helper that finds the PageTitle for the controller/action that you are currently rendering (using controller_name and action_name variables). If no match is found, then return the default.
#apeacox - is there a benefit of setting the title in the template? I would think it would be better to place it in the controller as the title relates directly to the action being called.
I prefer this:
module ApplicationHelper
def title(*page_title)
if Array(page_title).size.zero?
content_for?(:title) ? content_for(:title) : t(:site_name)
else
content_for :title, (Array(page_title) << t(:site_name)).join(' - ')
end
end
end
If title is called without arguments, it returns the current value of title or the default which in this example will be "Example".
It title is called with arguments, it sets it to the passed value.
# layouts/application.html.erb
<title><%= title %></title>
# views/index.html.erb
<% title("Home") %>
# config/locales/en.yml
en:
site_name: "Example"
You can also check this railscast. I think it will be very useful and give you basic start.
NOTE: In case you want more dynamic pages with pjax
I have a somewhat more complicated solution. I want to manage all of my titles in my locale files. I also want to include meaningful titles for show and edit pages such that the name of the resource is included in the page title. Finally, I want to include the application name in every page title e.g. Editing user Gustav - MyApp.
To accomplish this I create a helper in application_helper.rb which does most of the heavy lifting. This tries to get a name for the given action from the locale file, a name for the assigned resource if there is one and combines these with the app name.
# Attempt to build the best possible page title.
# If there is an action specific key, use that (e.g. users.index).
# If there is a name for the object, use that (in show and edit views).
# Worst case, just use the app name
def page_title
app_name = t :app_name
action = t("titles.#{controller_name}.#{action_name}", default: '')
action += " #{object_name}" if object_name.present?
action += " - " if action.present?
"#{action} #{app_name}"
end
# attempt to get a usable name from the assigned resource
# will only work on pages with singular resources (show, edit etc)
def object_name
assigns[controller_name.singularize].name rescue nil
end
You will need to add action specific texts in your locale files in the following form:
# en.yml
titles:
users:
index: 'Users'
edit: 'Editing'
And if you want to use meaningful resource names in your singular views you may need to add a couple of proxy methods, e.g.
# User.rb
def name
username
end
I thought it will be good:
<title>
<% if #title %>
<%= #title %>
<% else %>
Your title
<% end %>
</title>
And give a value to #title in your controller, or the title will be Your title
My answer is more simple:
locales/any_archive.yml:
pt-BR:
delivery_contents:
title: 'Conteúdos de Entregas'
groups:
title: 'Grupos'
And inside of application.html.slim:
title
= "App Name: #{t("#{controller_name.underscore}.title")}"
There's a simple way to manipulate layout variables (title, description, etc.):
# app/views/application.html.erb
<title>
<%= content_for :title || 'App default title' %>
</title>
# app/views/posts/index.html.erb
<%= content_for :title, 'List of posts' %>
And other pages will have App default title value for their titles
In application layout:
# app/views/layouts/application.html.erb
<title><%= (yield :title) || 'General title' %></title>
then in each view where you want a specific title:
<% content_for :title, 'Specific title' %>
There are already some good answers, but I'll add my simple approach. Add this to layouts/application.html
- if content_for?(:title)
-title = "My site | #{content_for(:title)}"
-else
-title = "My site | #{controller_name.titleize}"
You automagically get a nice names on all your views like "My site | Posts" -- or whatever the controller happens to be.
Of course, you can optionally set a title on a view by adding:
- content_for(:title, 'About')
and get a title like "My site | About".