Welcome/home page in Ruby on Rails - best practice
The question is, is your home page just a landing page or will it be a group of pages? If it's just a landing page, you don't expect your users to hang around there for long except to go elsewhere. If it's a group of pages, or similar to an existing group, you can add an action to the controller it's most like.
What I've done for my current project is make a controller named Static
, because I need 3 static pages. The home page is one of these, because there isn't anything to see or do except go elsewhere.
To map a default route, use the following in routes.rb
:
# Place at the end of the routing!
map.root :controller => 'MyController', :action => :index
In my case this would be:
map.root :controller => 'static', :action => :index
If you wish to, you could create a controller just for this home page. I'd call it main, or something that you can remember which relates to the home page. From there you can get your data and your models and defer to the output view.
class MainController < ApplicationController
def index
@posts = Posts.find(:all, :limit => 10, :order => 'date_posted', :include => :user)
end
end
Assuming you have your model relationships defined correctly, the template to match it will be very simple.
Good luck, hope this helps.
Rails - Best practice to have completely two different designs
The application.html.erb
file is considered a "layout" file, and the <%= yield %>
is where each controller can insert the page content into your overall layout.
You can have two different versions of things by simply adding another file along side application.html.erb
, named something like website.html.erb
. Now, in any controller you have, you can simply add to the top, layout 'website'
, and all controller actions in that controller will use the website
layout.
Using this, you can do some neat stuff:
- Have two layouts, one for your application (the wallet app itself), and one for your website (the public pages that don't require a user account). Each layout can include different CSS and JS
- Create a controller called something like
static_pages_controller
, which is meant for "static" pages (pages that do not largely change based on the user). For every page you want on the website, just add a controller action and an appropriate template. Tell this controller to use yourwebsite
template like above. - Because your static pages are going through Rails, you can even check if a user is logged in, and change your content as-needed, so instead of saying "Log In", you can say "My Account"
You can read more about Layouts on the official documentation.
Rails best practice for having same form on multiple pages
By any chance is your Post model in a belongs_to relationship with each model who's controller you'll be using to render your form? Are you doing any special processing in the Post controller beyond Post.create(params[:post])
?
If you answered yes to the first question and no to the second, you could get by with minimal mangling by adding accepts_nested_attributes_for to each of the controllers on which a user can create a post.
Regardless, Robertpostill is correct in that this is probably when to start looking at AJAX, to just replace the section of the page. The only problem is what to do if a user has javascript disabled. Personally I like to do design for the non-javascript case and add convenience methods.
As for thoughts on what you consider your two options,
1) I've used this method to store a shallow copy of an object in the flash hash. Preserving it across redirects. However this might not work for you given the variable nature of posts. As you can only send about 4K worth of data, and that includes other information in addition to your shallow copy.
2) See robertpostill's response
Best practice when developing an RoR application
Controllers should be RESTful, and should be appropriately named for the resources they manipulate.
The index
action of your PostsController
should have one purpose ... providing appropriate information relating to all of the posts to its view. The exact output of this could change within the view depending on whether you're logged in as an admin or not, but essentially the role of that action should be restricted to that function.
I would advise you to take a look at the CanCan gem and think about how you could use that to authenticate users, providing appropriate page content to admins and normal users alike.
Need explanation on best practices for sharing data amongst multiple methods of a controller
The first thing you need to understand is that each each HTTP request will be routed to a precise Controller#action
.
Rails will instantiate a new Controller
object for each request, and will then destroy these instances as soon as the requests they are serving have been completed.
This means that two requests from the same client, even if concurrent or subsequent, will be be handled by two different instances of the Controller
.
Also, if you decide to halt the execution of an action
by calling redirect_to another_path
, that will also be a different HTTP request, as rails will return the browser a 302 response with the new path as the destination of the redirection.
To answer your more practical question, you need to:
- store somewhere the state of your application (the file, the date and time of the upload, the user who uploaded it, etc)
- ensure that the
index
action has the means to retrieve that data.
On point 1, you can use the cookies, you can save that data in the DB and associate it to the user, etc.
On point 2, you can either retrieve that data using the user reference, or you can pass an explicit reference to the path helper, for example:
uploads_path
# => /uploads
uploads_path(custom_parameter: "ninja-turtles", upload_id: 1337)
# => /uploads?custom_parameter=ninja-turtles&upload_id=1337
done that, you'll have access to those parameters in the new action:
params[:upload_id]
# => "1337"
Just be careful, because passing sensitive data as part of the URL string means that anyone can try to supply manually crafted parameters.
If you don't want to use different actions, on the other hand, you can just render the index.html.erb
template at the end of the POST upload
action.
In Rails, actions will default to render the templates of the same name, but of course you can customize that.
Static pages in Rails?
There are a variety of approaches you can take (they're not all good approaches).
1 - public
directory
If it's truly static, you can put it in the public
directory. Things in the public
directory will be served immediately, without going through the Rails stack.
Advantages:
- Because it doesn't have to waste time going through the Rails stack, the client will receive a faster response.
Disadvantages:
- You won't be able to use your sites layout. Or view helpers like
link_to
. - Instead of your views being in one place (
app/views
), now they're in two places (app/views
andpublic
). This can be confusing.
Thoughts: I feel pretty strongly that the disadvantages outweigh the advantages here. If you're looking to make a minor improvement in speed at the expense of readability and programmer happiness, why use Rails in the first place?
2 - Place in app/views
and render directly from the Router
It is possible to render views from the router. However, it definitely isn't The Rails Way.
From the official RailsGuide on routing:
1 The Purpose of the Rails Router
The Rails router recognizes URLs and dispatches them to a controller's action.
Architecturally, there isn't anything inherently wrong with having a router map directly to a view. Many other frameworks do just that. However, Rails does not do that, and deviating from an established convention is likely to confuse other developers.
like should I create a controller or not?
Unless you want to take one of the approaches mentioned above - yes, you should create a controller.
The question then becomes what to name the controller. This answer outlines some options. I'll list them here with some thoughts. I'll also add three other options.
3 - Use ApplicationController
# routes.rb
get "/about" to: "application#about"
# application_controller.rb
class ApplicationController < ActionController::Base
def about
render "/about"
end
end
# app/views/about.html.erb
The advantage here is that you don't introduce overhead/bloat by creating a new controller and folder. The disadvantage is that it's not The Rails Way. Every controller you create inherits from ApplicationController
. ApplicationController
is typically used to house functionality that you want to share between all other controllers. See this example from the Action Controller Overview Rails Guide:
class ApplicationController < ActionController::Base
before_action :require_login
private
def require_login
unless logged_in?
flash[:error] = "You must be logged in to access this section"
redirect_to new_login_url # halts request cycle
end
end
end
4 - StaticController
or StaticPagesController
Michael Hartl's popular Ruby on Rails Tutorial uses a StaticPagesController
. I agree with the source I got this from in that I don't like this approach because the pages often aren't actually static.
Also, there is a possibility of confusion - why did we put other static views in separate controllers? Shouldn't static views be rendered from the StaticPagesController
? I don't think the possibility of confusion is too high, but still wanted to note it.
Also note Hartl's footnote:
Our method for making static pages is probably the simplest, but it’s not the only way. The optimal method really depends on your needs; if you expect a large number of static pages, using a Static Pages controller can get quite cumbersome, but in our sample app we’ll only need a few. If you do need a lot of static pages, take a look at the high_voltage gem. ↑
5 - PagesController
The official Ruby on Rails routing guide uses PagesController
. I think this approach is fine, but it isn't descriptive at all. Everything is a page. What distinguishes these pages from the other pages?
6 - UncategorizedPagesController
I would call the controller UncategorizedPagesController
, because that's exactly what they are - uncategorized pages. Yes, it's a little more cumbersome to type and read. I prefer the advantage of clarity over conciseness, but I could understand the choice to be more concise and go with PagesController
, or something else.
7 - High Voltage gem
With High Voltage, you don't have to do the tedious work of writing out routes and empty controller actions:
# routes.rb
root 'pages#home'
get '/about', to: 'pages#about'
get '/contact', to: 'pages#contact'
get '/help', to: 'pages#help'
get '/terms-of-service', to: 'pages#terms_of_service'
get '/landing-page', to: 'pages#landing_page'
...
# pages_controller.rb
def PagesController < ApplicationController
def home
end
def about
end
def contact
end
def help
end
def terms_of_service
end
def landing_page
end
...
end
You just add your pages to app/views/pages
and link to them: <%= link_to 'About', page_path('about') %>
.
Rails Separate Controller for Page with many Models? What is best?
You're right that this is more a RESTful dilemma and not related to any specific framework. It depends on the role of the Parent and Child Models and whether the dashboard 'exposes' any other additional resources. For the sake of simplicity I'm going the pretend the parent model is an Author and the child model is a Book.
If the dashboard only contains a collection of children related to a parent model you could consider using Nested Resources. E.g URLs similar to /authors/{author_id}/books
(and alias to /dashboard
if required):
# routes.rb
resources :authors do
resources :books
end
The logic then belongs in the BooksController
:
class BooksController < ApplicationController
def index
if params[:author_id]
@author = Author.find(params[:author_id])
@books = @author.books
return render '/books/author_index'
else
# Code for simple top level RESTful resource. E.g '/books'
# ...
@books = Book.all
return render 'index'
end
end
end
However if your dashboard is more broad and touches multiple domains, you could consider the dashboard as a resource in itself (e.g it's own DashboardController
) as described in this answer.
Related Topics
How to Configure Capistrano to Use My Rvm Version of Ruby
Understanding How Establish_Connection Works in Activerecord
Rails on Windows Is So Slow (Rails -V Takes 4 Seconds)
Rails Forms for Has_Many Through Association with Additional Attributes
Getting an Ascii Character Code in Ruby Using '' (Question Mark) Fails
How to Uninstall Ruby from /Usr/Local
How to Url Encode a String in Ruby
Spinning Background Tasks in Rails
Ruby on Rails: Can You Put Ruby Code in a Yaml Config File
Is There Equivalent for PHP's Print_R in Ruby/Rails
Gem Install Error (Sass Compass)
Ruby Gemspec Dependency: Is Possible Have a Git Branch Dependency
Add Nullable Foreign Key in Rails
Fail to Bundle Install Puma 4.3.5 or Gem Puma with Ruby-2.6.6 on MACos-10.15.6