Dynamic canonical tag - ruby-on-rails

Lately, I've been making my site more SEO friendly. Everything has been fun and games
until the canonical tag came along.
My site index is structured like the following.
example.com/all show all products.
example.com/all?brand=levis shows all products from Levi's.
example.com/jeans shows all jeans.
I would want to have dynamic canonical tags that refer to mysite.com/all, mysite.com/all?brand=current-brand and mysite.com/current-category.
The site also has a filter option for color and brands which produces slugs like mysite.com/hoodies?color=grey and mysite/hoodies?brand=nike&color=green. In both cases, I would want to have a canonical referring to mysite.com/hoodies
I made an attempt to fix this with an if else solution without success.
How it's set up now is like the following:
views/layouts/application.html.erb
<%= yield :canonical %>
views/pages/about
<%= content_for :canonical do %>
<link rel="canonical" href="example.com/about/" />
<% end %>
views/products/show
<% content_for :canonical do %>
<link rel="canonical" href="<%="example.com/#{#product.id}/"%>" />
<% end %>
These two works fine but when it comes to the index page it becomes trickier.
First I tried
<% content_for :canonical do %>
<link rel="canonical" href="<%="example.com/#{#category.slug}/"%>" />
<% end %>
This solution works fine when you go by category but crashes when you go to mysite.com/all or mysite.com/all?brand=levis.
I tried to experiment with some if else statements where I tried to target the current slug but it all ended up with crashes.
Do you guys have any suggestions of what I can do?

I somewhat solved the problem by placing
<% content_for :canonical do %>
<link rel="canonical" href="<%="example.com/#{#category.slug}/"%>" />
<% end %>
Under
<% if #category %>
It does not work exactly as I described in the questing since there is no canonical for example.com/all?brand=levis nor example.com/all. But that might even be better for SEO since google might take /all and /jeans for duplicate content, I'm not 100% sure. If you have another better solution, share and I would be more than happy!

Related

How do I use content_for

I'm trying to create a dynamic page title. Is more then just #project.title
The project title, in the page title contains many elements, like the project name, the project category and the project city.
I've tried this
<%= content_for :page_title #project.name, #project.category, #project.city %>
<%= content_for :meta_description, #project.description %>
But I get an error like this one
syntax error, unexpected keyword_ensure, expecting ')'
I've also tried
<%= content_for (:page_title #project.name, #project.category, #project.city) %>
which resulted in the same error: syntax error, unexpected keyword_ensure, expecting ')'
Basically it's just a syntax error. If you want to store a block you use <% content_for :page_title, "My title" %>. Only if you want to reuse this block, you should add a = after the opening tag.
According to the docs you can only pass one content parameter. So you have to do the concatenation by yourself.
<% content_for :page_title, "#{#project.name} #{#project.category} #{#project.city}" %>
The documentation for the content_for helper can be found here.
quick answer
Maybe, just try this in your Project view
<% content_for :page_title, "#{#project.name} #{#project.category} #{#project.city}" %>
tl;dr
content_for stores a bit of code in an identifier. In order to access this stored content later you have to pass the identifier as an argument to content_for.
Note: yield can still be used to retrieve the stored content.
Or in other words, the content_for method allows you to insert content into a named yield block in your layout.
for example
If your current layout contains a yield(:title) ...
<!-- app/views/layouts/application.html.erb -->
<html>
<head>
</head>
<body>
<div id="title"><%= content_for?(:title) ? yield(:title) : "No title block!" %></div>
<div id="main"><%= yield %></div>
</body>
</html>
Then you can insert a title from a view like this
<!-- app/views/projects/index.html.erb -->
<% content_for :head do %>
"#{#project.name} #{#project.category} #{#project.city}"
<% end %>
See: https://api.rubyonrails.org/classes/ActionView/Helpers/CaptureHelper.html#method-i-content_for
and https://rubyplus.com/articles/3081-Layouts-and-Content-For-Tag-in-Rails-5
To answer your question. The error messages you receive tell you that your Ruby code is syntactically incorrect. In idiomatic ruby, it's always wrong to call functions the way you've shown us. Parameters must always be called individually, separated by a comma:
# wrong code, wrong syntax
<%= content_for :page_title #project.name, #project.category, #project.city %>
# wrong code, right *right syntax*
<%= content_for :page_title, #project.name, #project.category, #project.city %>
Also as pointed out in Robin's answer, the docs for content_for show that you can only pass one content parameter. So you have to do the concatenation by yourself.
<% content_for :page_title, "#{#project.name} #{#project.category} #{#project.city}" %>

Canonical link in head of home page on Rails

I'm trying to have a line in the head of my home page for my rails site. This should be:
<link rel="canonical" href="http://negotiatus.com" />
On my personal dev copy of the site, it appears perfectly in the head of the home page. However, on the production version of the site it does not. I believe it has something to do with Rails precompiling stuff, but I could be wrong.
If someone could point me in the right direction here that would be great
Relevant part of the home view:
<% content_for :for_head do %>
<link rel="canonical" href="http://negotiatus.com" />
<% end %>
In my application.html.erb:
<% if content_for? :for_head %>
<%= yield :for_head %>
<% end %>
It shows up if I inspect the source of my local dev copy, but doesn't show up if I view the source of the production version (hosted on heroku).
I retried precompiling everything, then committed and pushed everything again, now it works.
Sorry for wasting anyone's time.

why does the script affect everything on my Rails 3 app even when cased in this code?

I have a third party script which is
<script type="text/javascript" src="http://thirdpartysite.com/front.asp?id=xxxx"></script>
What the script does is put a watermark on an image to show that it is copyrighted.
This is the code that I'm using in view, but no matter what, the script applies to all posts
<% if post.copyright == true %>
<script type="text/javascript" src="http://thirdpartysite.com/front.asp?id=xxxx"></script>
<% else %>
<% end %>
When I test it using text only, it works correctly
<% if post.copyright == true %>
Sample text here only applies to post where copyright==true
<% else %>
<% end %>
How can I get the script to only apply to certain posts?
After your clarified in a comment
Yeah, including javascript will apply pagewide if nothing else is specified in the javascript.
You need to do something like:
<div class="post <%= 'copyright' if post.copyright%>">
<img src="somesrc.jpg"></img>
</div>
and then apply the javascript only to the css selector 'div.copyright img'. Something along the lines of that. Depends on what the javascript supports or if you can change the source.

RoR: How do I validate my pages when sometimes I have CSS links not in the HEAD?

I get this error when using the w3 validator: document type does not allow element "link" here
I mean, I know style links are suppossed to be in the head, but for an RoR project, it's more.. efficient? to only load what you need? cause, lets say, A stylesheet is loaded in a partial. and that partial is used on multiple pages. It makes sense, as far as DRYing things up goes, to include the stylesheet with the partial.
But it seems like DRYing things goes against W3C.
What do I do?
You shouldn't be putting <link> elements into your content like that. You can use ERB's blocks to yield the content into another part of your layout template, like this:
<% content_for :head do %>
<%= stylesheet_link_tag 'my_partial_styles' %>
<% end %>
<p>Your partial content...</p>
In your application layout, you can yield this content where it belongs:
<head>
<%= yield :head %>
</head>

Rails rendering content_for not working for partials

I am using a Rails 2.3.8 application. I have a layout file that contains
<%= yield :head %>
I called the following code in different parts of my application:
<% content_for :head do %>
<meta name="keywords" content="" />
<% end %>
I tried to add that code in a view file home it worked. I called it from patial _abc that is called from home it also worked as expected by adding the meta code in the head part. But when I added the code inside partial _def that is called from _abc which is called from home the meta tag did not show up!!!
I didnt usderstand what is going on... and how can bypass this problem
UPDATE: The case that did not work was:
home.html.erb:
<%= render :partial=>"_abc"%>
_abc.html.erb:
<%= render :partial=>"_def"%>
_def.html.erb:
<% content_for :head do %>
<meta name="keywords" content="" />
<% end %>
Thanks a lot
This is an old question, but I got here with a similar issue. Figured I'd post my issue/solution in case someone else lands here.
Which file is <%= yield :head %> in? I had this issue and it turned out my yield was in the "/layouts/application.html.erb" file... But the view being called was using a different layout file i.e. "/layouts/listings.html.erb". once I moved the yield into the correct file, everything worked fine, and I had pretty much the same setup you described.

Resources