Categorize webpages for layout and CSS purposes in Rails - css

I have a lot of different webpages, but most fall into 1 of 6 or 7 categories of pages. For each of these categories of webpages, I have a slightly different look and feel, like different background colors/images. I have the following in views/layout/application.html.erb:
<header class="sub<% if content_for?(:page_type) %> <%= yield(:page_type) %><% end %>">
And in every single view, I have:
<% content_for :page_type, 'information' %>
But it's really a pain to do that for every single webpage and when I want to change things around I keep having to mess with these (I have a ton of pages). So, instead I'm thinking to just use a variable:
<header class="sub<%= #page_type ? ' ' + #page_type : '' %>">
and for views:
<% #page_type = 'information' %>
The advantage is I could do a before_filter :set_page_type in the controller and set the page type once for all the views it controls (a big help).
Maybe the best thing for me to do is just use the first folder of the URL as the category of the webpage. I'll have to restructure the URLs, but that might make sense to do so anyway. I do have some top-level pages that would have to remain so.
This has to be a fairly common situation, what is the best way to categorize most pages and use that categorization in layouts?

I’m usually using a helper for the body class — something like this:
def body_class(c = nil)
#body_class ||= [controller.controller_name]
#body_class << c
#body_class.flatten.compact.uniq.join(" ")
end
This will by default include the controller name (you could also include the action etc..
Then I call this helper in views as needed, e.g.
<% body_class "bar" %>
Since the helper always returns a class string, you can then call the same helper in you layout (I use the body tag), likely without arguments:
<body class="<%= body_class %>">
Which would render in the previous example for a controller called FoosController the following:
<body class="foos bar">
If you define the helper in e.g. the application controller and make it available to the views using helper_method, this should hopefully much do what you’re after.

Related

How to manage a list elements staying on the same page

By default, rails has controller CRUD actions with corresponding routes. For instance, I have a simple bookstore app, where I have a book and category. I want to display all categories through a sidebar on a home page. Each category is a dropdown element accompanied with a books count integer. When expanding a dropdown I want to see a book title that belongs to a current and acts as link. That is easy to implement.
The question is how can I add a form hidden under, let's say a + sign, sticked next to a static Dropdown section title "Categories" if there are none?
A form for Create action in Category controller which would allow to create a new category and display it straight away without redirecting to Create category view and redirecting back.
Please advise any reliable solution or tutorial link. Thanks a lot.
It looks like you are looking for an AJAX form. In rails you can generate this with form_for ... remote:true. This can call a controller method with out refreshing the page. You can then return a response and use JS to update the page the user is on.
For example, in your view
<div class="hidden">
<%= from_for #category, remote:true %>
Your form here
<% end %>
</div>
Add in some JavaScript to un-hide the form when your button is clicked. In your controller
def create
#normal create stuff
if save
respond_to do |f|
f.js
f.html {#re render page just in case JavaScript is disabled}
end
else
#handle error
end
end
using the rails default f.js, Rails will call a file create.js.erb this file will have access to any public variable you make, for instance #category.
you can then do somthing along the lines of
$('.append_category').append('<%= j render 'your category layout partial', locals: { category: #category }%>');
or if you just need the category link
$('.append_category').append('<%= link_to #category %>');
A very nice guide can be found here http://guides.rubyonrails.org/working_with_javascript_in_rails.html
Note: depending on your version of rails, you may need to add include ActionController::MimeResponds to your application_controller.rb (I know this is required in rails 5)

How to create dynamic CSS based on user input

A user should be able to design a room (room is a model) in my Rails app. When the user visits myapp.com/room/1 the room with its content and specific design is shown.
The design or CSS of the room is based on room parameters (color1, color2, ...) and some random generated design characteristics (font type, image border, ...). These characteristics are stored in the room model when the room is saved.
I don't see how I can generate a specific CSS for each room. When the user visits myapp.com/room/1 my app should build specific CSS (or SCSS) for room1. Where (what controller) should I build that CSS?
Thanks
You can make your RoomsController respond to the CSS format as well in order to get this to work:
# app/controllers/rooms_controller.rb
class RoomsController
def show
#room = Room.find(params[:id])
respond_to do |format|
format.html
format.css
end
end
end
Then you need to implement a template to be rendered for the CSS format:
/* app/views/rooms/show.css.erb */
.room {
background-color: <%= #room.color1 %>;
color: <%= #room.color2 %>;
}
Note how this is very similar to a regular template. You need to make sure that this results in valid CSS.
You need to make sure the stylesheet is included when the user visits the page. Let's say a user can browse their room design when they visit /rooms/1. This will render a HTML template, which we could define as follows:
<!-- app/views/rooms/show.html.erb -->
<% content_for :stylesheet_includes do %>
<%= stylesheet_link_tag(room_path(#room, format: :css)) %>
<% end %>
<div class="room">
Room Contents Here
</div>
Notice that I've used content_for around the stylesheet link tag. We can use this to make sure the stylesheet link tag is rendered nicely in the head of the layout:
<!-- app/views/layouts/application.html.erb -->
<head>
<%= yield :stylesheet_includes %>
</head>
Of course you'll need to fill in the details yourself, but this would be the most logical approach for the problem.
If you design your controller to respond to the show action with json requests, you'll be able to retrieve the attributes of the Room object in json format
http://localhost.com:3000/rooms/1.json
{"id":1,"color1":"black","color2":"green","created_at":"2014-12-15T19:52:21.235Z","updated_at":"2014-12-15T19:52:21.235Z"}
In that case, you can use javascript to make the get request, retrieve the data in JSON, and subsequently use that data to manipulate the dom.
$.get( "rooms/1.json", function( data ) {
alert(data);
});

What would be the best way to have a different navbar for my home page than the rest of the site in rails?

I have two nav bars, one for the home page, and one for the rest of the site. I'm not sure how to go about doing this in a good DRY way. It seems like i want to put the rest of the sites navbars in the layouts views, but I don't know how to exclude a layout from a page I guess? The rest of the home page layout is the same as the rest of the site, so the only thing I would want to exclude is the nav bar for that page and replace it with another. The links will also be the same. So navigation_links can also be rendered in both.
There are multiple solutions to this problem, but the one I like most is taking advantage of Rails' Template Inheritance. Let's say your home controller looks like this:
class HomeController < ApplicationController
end
Rails looks up the layout for the views rendered by this controller by its name, home. If there's no such layout, it will look for one named after its super class, application and so on. This is explained in the Rails documentation.
Looking up partials actually works the same way. Let's say you were to render a partial navigation_bar in your layout:
render 'navigation_bar'
If you don't specify its exact location (like application/navigation_bar, Rails will again use template inheritance to look for the partial.
So first it will look for home/navigation_bar, and then for application/navigation_bar. You can use this to your advantage if you only want to display a different navigation bar, without redefining the layout or anything else.
So you need to place your general navigation bar in application/_navigation_bar, and your home navigation bar in home/_navigation_bar. Then render the navigation bar in your layout:
render 'navigation_bar'
Use the content_for helper method.
In your view template, perhaps application.html.erb, you can do:
<% if content_for? :nav %>
<%= content_for :nav %>
<% else %>
<%= render 'layouts/nav' %>
<% end %>
Then in your home page:
<% content_for :nav, render('layouts/custom_nav') %>
Personally, I prefer this method—it's declarative, it lets others (including future you) know explicitly that the default nav can be overridden.

Escape field inside Control loop

New to SilverStripe and trying to decypher how things work.
I have a field in a page which I used to store some HTML code. When you view their "Holder" page, it loops over each child page and displays them all. The problem I am running into is that when I output the value it's escaping it - so I need to be able to decode it.
<% control Children %>
<h2>$Title </h2>
$ExtraHtmlBody <!-- This is escaping when outputting -->
<% end_control %>
So I tried to add a function inside my Page_Controller, but it seems that I can not call Page_Controller methods from inside the Control loop. I tried moving the function into the Page class, but it doesn't seem to have any data for $this->ExtraHtmlBody. Maybe I'm doing something wrong.
You data might already be escaped in the database itself. did you check?
Like #munomono said, if you are storing html use HTMLText or HTMLVarchar.
You can also try to disable auto-escaping in your template with $ExtraHtmlBody.RAW (at your own risks).
some info here:
http://doc.silverstripe.org/framework/en/topics/data-types#casting-html-text
http://doc.silverstripe.org/framework/en/topics/security#what-if-i-can-t-trust-my-editors
http://doc.silverstripe.org/framework/en/reference/templates#formatting-and-casting
Your controller function problem is probably just a scope issue since <% loop %> changes the scope, $Up/$Top might help. But you probably don't need that function anyway.

How to get "Title" attribute from the "Page" object

I use SilverStripe as the CMS and I'm stuck now and don't know how to access "Title" attribute from the "Page" object.
I tried:
$Event.Trainer.Title
But it doesn't work. The "Trener" is the "TrenerPage" object. How can I access to Trener->Title attribute?
You can't traverse three levels in SilverStripe templates (at least in version 2.x). Two is the maximum.
What you need is something like this:
<% control Event %>
$Trainer.Title
<% end_control %>
Your question seems to inconsistently switch between "Trainer" and "Trener", I'm guessing one of those is a typo?
If the template is for the page you wish to display the title of, all you need to use is $Title in your template and it will output the title of the rendering page.
If the template is NOT for the page you wish to display the title of, then like xeraa said, you should use a control block.
The title is directly within the Page object.
Just using $Title should do the trick. To help you with all the methods available in the Page object go to:
http://doc.silverstripe.org/sapphire/en/reference/built-in-page-controls
Since the question is not very clear, I'll take a shot at another answer.
If you derived the Trainer_Page from the Page object it still inherit the $Title attribute directly. Unless you overider the $Title attribute yourself in the Trainer_Page object, PHP will default it back to the parent class. In that case just use $Title.
Beware of the case as $title and $Title are not the same.
Good luck.

Resources