My project is to make a website with html5 games, in Rails.
I have a controller called games_controller, and I would like to match /games/name-of-my-game with each html5 games. I created a route, matched with a games_controller function, but here is my problem:
I want everything to be "plug-and-play" for my html5 games, I mean develop them out-of-Rails, then just copy/paste it inside my app and everything works fine (references to images,.js files and all). But I also want my game's view to be inside my application layout. Here is what I tried :
Put it in /public directory, and in my games_controller's show method do render "/public/path_to_my_game". This breaks all references like <script type="text/javascript" src="some_script.js"></script>, cause the url isn't */path_to_my_game* but /games/name-of-my-game.
Put it in /public directory, but with a redirect_to in my show method instead render. The references are not broken, but the layout is gone (I may be wrong, but layouts are stuck with controllers, not static files).
Put it in app/views/games but this seemed ugly so I quickly stopped :).
Does anyone have an idea ?
If you have something like
# config/routes.rb
match '/games/:game' => 'games_controller#show'
# app/controllers/games_controller.rb
def show
#game = params[:game]
end
All you really have to do in your layout file is
<%= javascript_include_tag #game %>
This means you will have a app/assets/javascripts/<game>.js file for each game you have. It will be responsible for booting each game.
Obviously, you will want to take precaution to validate that params[:game] is a valid game.
Alternatively, you could create a content section in your layout file
<html>
<head>
<%= yield :game %>
</head>
<!-- rest of layout ... -->
Then serve the appropriate view with your GamesController
# app/controllers/games_controller.rb
def show
#game = params[:game]
render "games/#{#game}"
rescue ActionView::MissingTemplate
redirect_to root_path, :alert => "invalid game id"
end
Then in your game views, you will require all necessary files for each game. For example, a user visits /games/pacman
# app/views/games/pacman.html.erb
<% content_for :game do %>
<%= javascript_include_tag 'pacman/foobar' %>
<%= javascript_include_tag 'pacman/start' %>
<%= stylesheet_link_tag 'pacman/styles' %>
<% end %>
Another example, user visits /games/time_pilot
# app/views/games/pacman.html.erb
<% content_for :game do %>
<%= javascript_include_tag 'time_pilot/init' %>
<%= stylesheet_link_tag 'time_pilot/base' %>
<%= stylesheet_link_tag 'time_pilot/retro' %>
<% end %>
Because I'm sure each game is going to have a different amount of dependencies and they will all be initialized differently, you can build the view for each game accordingly and serve up whatever assets are relevant to each game.
Fore more help with with layouts and rendering, see the rails guide: Layouts and Rendering in Rails
Related
I'm creating a rails app and I must differentiate the header for home page.
I already created a partial with the _home_header version and the _header version to use in every page, but I don't know how can I manage the change.
The header is included in my layout, and I render the same layout for every page. How can I tell to "layout" to use the _home_header version instead of the standard version when I request homepage?
I would use the current_page? helper and look at the root_path.
# app/views/layouts/application.html.erb
<% if current_page?(root_path) %>
<%= render 'layouts/home_header' %>
<% else %>
<%= render 'layouts/header' %>
<% end %>
Use something like this in application.html.erb
<% if request.original_url == root_url %> ## Specify the home url instead of root_url(if they are different)
<%= render 'layouts/home_header' %> ## Assuming that _home_header.html.erb is under layouts directory
<% else %>
<%= render 'layouts/header' %> ## Assuming that _header.html.erb is under layouts directory
<% end %>
Typically, you add more specific versions of pages in controller-specific sub directories.
That is, if you have a layout application.html.erb which renders a header partial...
# app/views/layouts/application.html.erb
<!doctype html>
<html>
...
<body>
<%= render 'header' %>
...
This will look for a header partial first in app/views/<controller_name>/ then in app/views/application/. So, your site-wide header would reside in app/views/application/_header.html.erb, and your homepage partial would reside in app/views/home/_header.html.erb, and it would "just work". Rails would load the more "specific" header.
An option to #meagar suggestion would be use a before_action on your application controller for that:
class ApplicationController
beore_action :set_header
private
def set_header
#header = if is_my_page
"Special header"
else
"Other header"
end
end
end
and in your layouts/application.html.erb:
<title><%=#title%></title>
The bright part of his solution is that all text are kept on the view files, which makes sense. The not-so-bright part is that is harder to follow.
I'm trying to use Rails with Angularjs. Angular will do all the client side work while Rails controllers suppose to handle requests to list and modify information (in Database).
I have a simple template in views/layouts/application.html.erb:
<!DOCTYPE html>
<html>
<head>
<title>SomeApp</title>
<%= stylesheet_link_tag "application", :media => "all" %>
<%= stylesheet_link_tag "vendors", :media => "all" %>
<%= csrf_meta_tags %>
</head>
<body>
<div id="wrapper" ng-app="app" ng-controller="AppCtrl">
<div ng-controller="SomeApprCtrl">
<%= render 'header' %>
<div ng-view=""></div>
<%= render 'footer' %>
</div>
</div><!-- End on wrapper -->
<%= javascript_include_tag "application" %>
</body>
</html>
This template does everything i need to start Angular. But i need to put something in Rails routes. I need to define controller and action. Say something like this:
root :to => 'main#index'
And this mean that I need to define controller Main with only one empty method index and totally empty template file in views/main/index.html. How can i avoid appearance of this empty useless files?
I was thinking of using root :to => 'application#index' and define empty index method in ApplicationController but since this controller is basic for inheritance to all other controllers i don't want them to have any crap. Also this approach does not solves problem with empty index.html template
While it is empty the controller is actually handling a lot by convention. It automatically displays the index.html.erb view, and since the layout hasn't been specified it wraps it in the application.html.erb layout.
So while the file may be sparse there's a lot going on behind the scenes.
I am new to rails. I am having difficulty in understanding template inheritance. Earlier I have worked in django and seen template inheritence there. There I saw child is told about parent using "extends" command. Can anyone explain how it works here. I have gone through guidelines of ruby but it was not clear.
Thanks
It's quite simple to do in Rails.
You simply tell the template you are currently rendering to render another template.
For example layouts/application.html.erb contains something like this:
<% content_for :navigation do %>
<nav>...</nav>
<% end %>
<% content_for :content do %>
<%= yield %>
<% end %>
<%= render :template => 'layouts/main_application' %>
The important part is the render :template part that then delegates this template to also render the layouts/main_application.html.erb that in my case looks something like this:
<header>
...
</header>
<body>
<%= yield :nav %>
<%= content_for?(:content) ? yield(:content) : yield %>
</body>
What I am doing here is having a main template that does not contain the navigation (for things like login etc) and the application.html.erb adds that navigation to the :nav content placeholder.
I have a stylesheet, application.css defined in layouts/application.html.erb:
<%= stylesheet_link_tag "application" %>
However, there's a section of the site where the views will use a completely different stylesheet, dashboard.css which I've defined in its index.html.erb:
<head>
<title>My title</title>
<%= stylesheet_link_tag "dashboard" %>
..
Unless I remove the stylesheet_link_tag in the application layout file, there are conflicts which make the dashboard view weird. If I move the application layout stylesheet tag to a _header.html.erb partial which is rendered with every view in the non-dashboard section like below, it doesn't work. How must I call them?
<%= stylesheet_link_tag "application" %>
<header>
<div id="headercontainer">
..
you should use a yield statement in your application.html.erb in the head element as such:
<head>
<%= yield :head %>
</head>
then in your view, you would use a content_for tag:
<% content_for :head do %>
<%= stylesheet_link_tag "dashboard" %>
<% end %>
also read the rails docs on nested layouts. it'll teach you how to get fancy with this paradigm
Create a separate layout for your dashboard, with specific stylesheets.
If you want customized stylesheet for one of your controllers (and all of its actions), it's quite easy to do. Create a layout with matching name, that is, for your users_controller, template name should be users.html.erb.
Also you can specify any layout for controller.
class UsersController < ApplicationController
layout 'some_layout'
end
If you want custom stylesheet only for some actions, specify corresponding layout in call to render.
def dashboard
# some logic here
render :layout => 'some_layout'
end
I would suggest you define a second layout for dashboard (app/views/layouts/dashboard.html.erb). From that layout link to the dashboard stylesheets. Then use that layout from your dashboard views or controllers.
Oh just use some if conditions to link different stylesheets in the same layout:
<%= stylesheet_link_tag(dashboard_views? ? "dashboard" : "application") %>
Just implement dashboard_views? helper method to return true or false based on your views.
Sorry for the slightly noobish question, as I am writing my first rails app.
I get the idea of the layout view, but if you are using them, is there any way to include a view specific js or css file? For example, I have layouts/products.html.erb, and for products/edit.html.erb I want products_edit.css, but I don't want that css for all product views, what is the best practice to accomplish that?
If you have a generic edit.css file, I would suggest an if in your layout
<%= stylesheet_link_tag 'edit' if params[:action] == 'edit' %>
Otherwise you can use content_for with a yield to add additional tags into the head.
layout.html.erb
<head>
...
<%= yield(:header) if #content_for_header %>
</head>
products/edit.html.erb
<% content_for :header do -%>
<%= stylesheet_link_tag 'edit_product' %>
<% end -%>
You can add a stylesheet tag inside the head tag of the layout by doing something like this:
layouts/products.html.erb:
<head>
...
<%= yield :css %>
...
</head>
products/edit.html.erb
<% content_for :css do
stylesheet_link_tag 'products_edit'
end %>
You can't if your </head> tag is in your layout.
You may want a different layout for that controller action. Like this on the render:
render :action => "index", :layout => "some_other_layout
Also you can set a different default layout for a whole controller with this line in the controller class:
layout "some_other_layout"
Check the API docs, there's some complex things you can do with conditionals on that layout method.