Customizing Devise views in Rails - ruby-on-rails

I'm using devise for user auth, but I have nice mockups for the signup, login, etc. pages.
I've already done the rails generate devise:views User command and have all of the views in the views folder, however, when I replaced the registration/new.html.erb with my own new.html.erb, nothing changes nor looks different. It's as if I had done anything.
Anyone know what I'm doing wrong or at least how to successfully customize devise views
P.S. Is it important to note that I changed the route of devise/registration#new to /signup?

at a glance answer.
...instead of
rails generate devise:views User
use:
rails generate devise:views
If you've already done it, move the folders devise created from app/views/User to a new folder app/views/devise (or just rename the User folder to devise, if that's an option.)
Those folders are:
app/views/User/confirmations
app/views/User/mailer
app/views/User/passwords
app/views/User/registrations
app/views/User/sessions
app/views/User/shared
app/views/User/unlocks
No other changes are necessary.

though this is an old question, I thought I'd add to it in case anybody stumbles on it. I'm not sure if this is a new addition since the question was originally asked but if so the simpler (more modern) approach is this.
in the file config/initializers/devise.rb there is the following block of code:
# ==> Scopes configuration
# Turn scoped views on. Before rendering "sessions/new", it will first check for
# "users/sessions/new". It's turned off by default because it's slower if you
# are using only default views.
# config.scoped_views = false
by uncommenting config.scoped_views = false and changing it's value to true, devise will automatically check whether the custom view exists and if so, serve that up.
As the comment says, it may add some overhead to the application but in my experience so far, this is negligible.

Your route signup or devise/registrations#new will render the view
views/devise/registrations/new.html.erb. It sounds like you made
changes to views/user/registrations/new.html.erb, which would explain
why you dont see the changes made since its not being rendered.
You will either need to create a user/registrations_controller.rb that
extends from Devise::RegistrationsController and point your /signup
route to user/registrations#new, or you can just make your changes
directly to views/devise/registrations/new.html.erb
Same idea applies to your login (devise/sessions) pages.
Hope this helps.

For anyone still having a problem with this, the problem lies in the call to rails generate devise:views User. It should be rails generate devise:views for fetching current views from the Devise Rails Engine. This will generate proper views which will work with the default routes.

After generating your custom views e.g
rails generate devise:views User
Turn on scoped_views in config/initializer/devise.rb
view config.scoped_views = true
And you are done.

I had the same problem until I went back and read the devise documentation :)
After rails generate devise:views make sure you go into initializers/devise.rb and set config.scoped_views = true. This is explained in the devise documentation at https://github.com/plataformatec/devise as well as in the devise.rb comments.
After I did this, my own views in views/users started showing up instead of the ones in the gem.

Using rails g devise:views User allows you to customize when you have more than one role.
the proper way to do this is going into your devise.rb in config/initializer/ folder
and uncommenting and setting config.scoped_views = true.
now you can edit the view erb files without any problems

For future reference, you can just rename folder from devise => user and vice versa and rails will find a route.

Related

Where is the code that Devise generates?

I installed the Devise gem into my Rails app, and ran rails generate devise:install and rails generate devise User.
Without my doing anything, the url users/sign_up already has a view somehow. The problem is, I can't find the template that is being rendered anywhere. It's certainly not under app/views/users. I chose some text on the page and ran a search for it within my app, and got back 0 results.
Then I tried to sign up with the form, and got the following error:
NoMethodError in Devise::RegistrationsController#create
undefined method `current_sign_in_ip' for #<User:xxxxxxxxxxx>
I then searched for this controller, but there is no RegistrationsController in my app, and no Devise file. None of the files I'm looking for were generated by the two commands I mentioned above, either.
The Devise documentation doesn't seem to shed any light on where the Devise code is kept.
Is the code even in my app? I'm so confused.
Using Devise, you're able to generate the templates which Devise depends on for logins, password resets, etc. using the following command:
rails generate devise:views
This will create copies of the templates for Devise in your views directory.
For controllers, you can access/override their functionality by subclassing them in your own code. They're under the Devise namespace:
class NewRegistrationsController < Devise::RegistrationsController
# do stuff here
end
Then point the router to use this new controller:
devise_for :users, controllers: { registrations: 'new_registrations' }
The code for the controllers can be found in Devise's source code - you can reference it to better understand what each controller is doing.
Hope that helps!
This is standard practice for Rails "engines" (which almost all gems are) -
Think of them as libraries / dependencies... wherein they provide access to a lot of pre-compiled functionality through several hooks (often provided by an API).
One of the reasons I'd actually recommend people to write their own gem is because it helps you appreciate how the whole thing works. I wrote a gem, it uses views just like Devise:
These views are not seen in the application because they're appended to your Rails app at runtime. It's basically how the PATH var works in cmd, if you've ever had the pleasure of working with programmatic compilation etc.
Thus, Devise's "views" are stored in the Devise gem. This is appended to your Ruby installation... [Ruby install dir]/lib/ruby/gems/[ver]/gems, loaded at RunTime just like the PATH var...
Whilst you can generate your Devise views (as mentioned in the other answers), this is the base line of how it's able to access them without any prior references.
NoMethodError in Devise::RegistrationsController#create
undefined method `current_sign_in_ip' for #<User:xxxxxxxxxxx>
This means you don't have the current_sign_in_ip attribute for your Devise installation. I answered your question about this specifically here...
Devise error: undefined method `current_sign_in_ip'
All the devise MVC files are inside the gem. Below is my devise views directory. You could check yours as well. Go to your project root.
gem show 'devise'
/Users/saurabh/.rvm/gems/ruby-2.1.0/gems/devise-3.2.4
cd /Users/saurabh/.rvm/gems/ruby-2.1.0/gems/devise-3.2.4/app/views
You can generate views in your project if you wish to customize.
rails generate devise:views
All code of devise can be easily go through by devise and if you are using rubyMine you can view devise code in external libraries in devise folder.
To generate template for your model
rails generate devise:views
and then you can change your view as you want for your application.

where are the auto generated routes in rails scaffolding?

Alright, I'm starting to learn rails and so far im really turned off by how much is auto generated and happening behind the scenes without me knowing. I generated scaffolding for posts. and it auto created routes allowing me to edit and see posts (/posts, /posts/:id/edit, /posts/:id/show....etc) When I go into config/routes.rb I see absolutely no mention of these routes. even though they work. Where are these routes? and where can I add custom routes if the ones for the controller are not in routes.rb?
When you run rails generate scaffold post, rails will generate models, controllers, tests, routes, stylesheets etc.
Rails tells you what files it just generated, you can see it in terminal.
In routes.rb there will be a line
resources :post, this is a shorthand for all RESTful actions that were generated in the controller.
You can declare custom routes in the routes.rb file. I.e.:
get 'my_path'=> 'my_controller#my_action'
In General, Rails can do a lot of stuff for you, and you can avoid repeating default behaviour over and over again. But you can also do most stuff yourself, without Rails magic.
Instead of using scaffolds, just run rails generate controller controller_name action1 action2 (..). You'll end up with just a controller, no automatic views, no automatic model etc.
Or you can just create all files and register your components yourself.
The Rails Guides are a good starting point for understanding the magic.

How to create a simple Rails app with only a controller /view page ,avoiding all the unnecessary files in my app

I have a Rails app which contains a single controller(with a method) and a single view page .I would like to avoid all the unnecessary files in my app to keep this in a simple way. I need an app with controller,routes and views. So how should I scaffold my Rails 3 app, so that it contains only a minimal information?
If you are working on a real simple app, probably you the best fit would be sinatra
That is not rails, but implement with ruby.
HTH
You can manually create the files, especially when you only need a small portion of what the scaffold would create.
1) Add a statics_controller.rb to the app/controller directory. If you literally only need one page, you can simply use the index action (name your method index).
2) Add an index.html.erb (or .haml) to the app/views/statics/ directory.
3) In your config/routes.rb add the line get '/statics' => 'static#index'. You can append , as: 'your_preferred_url if you want to define your own url.
In all of the above, replace "static" with whatever name you think is appropriate. You would also need to add a model and migration if you plan to interact with a backend database.
I personally feel its good to not use scaffolding initially when you are new to rails so that you fully understand what they are doing. Scaffolding is not really doing anything fancy or magical. Its often just creating empty files in the correct directories (like I outlined above).
You can use the rails scaffold to be very specific in which part of MVC you create. For example,
$ rails generate controller Comments
or
$ rails generate model Comment commenter:string body:text post:references
I would highly recommend reading the entire Rails Getting Started Guide. But there is a specific section on generating a controller with scaffold.
Since Rails 6.1. running rails new --minimal gives you an application without all the bells and whistles like action mailer, action mailbox, action text, action job, active storage, action cable, ... and the accompanying configuration and stub files. It then has an ApplicationRecord, ApplicationController and the basics for an HTML view.

Setting locale on a per-user basis when using devise and rails 3

I have just been through one of my apps converting the authentication from authlogic to devise. By and large this has been amazingly straight-forward to do but there is one issue I can't find an easy fix for.
In the app, the user has the option of choosing their locale. Then whenever they login, they view the app in the language they choose. Previously, I did this by simply setting the locale in the create method of my UserSessions controller.
With Devise, all the controllers are automatically setup, which is great. I know that I could create a custom Controller that extends the DeviseController and do it like this but, from what I understand, that means that I will also need to create all the views to go with it which seems a bit over the top when I just need to run one extra line of code.
Is there an easier way of specifying some code to be run on a successful devise authentication?
I found the solution I was looking for here
As I just wanted to set the locale for the user when they logged in, all I needed was to add the following method to my ApplicationController
def after_sign_in_path_for(resource_or_scope)
if resource_or_scope.is_a?(User) && resource_or_scope.locale != I18n.locale
I18n.locale = resource_or_scope.locale
end
super
end
Have you executed rails generate devise:views? This will output the Devise view files for you, and then you should be able to move them to a location that matches your new extended Devise controller name.
Devise is locale aware, which means that your views should automatically load language translations for you.
All you need to do is provide a "devise.[:locale].yml" file in the root "locales" folder of your rails application for each language translation that you wish to support.
The Devise wiki has a bunch of locale translations that have been provided to save you some work:
https://github.com/plataformatec/devise/wiki/I18n

Renaming controllers in Rails and cleaning out generated content

I was following along with the railscast regarding the restful_authentication plugin.
He recommended running the command:
script/generate authenticated user session
Which I did, and everything generated "fine", but then sessions wouldn't work. Checking the site again, he mentions a naming standard and listed updated code which stated:
script/generate authenticated user sessions
With sessions being pluralized.
So now I have session_controller.rb with a SessionController in it, but I guess by naming standards, it is looking for SessionsController, causing the code to fail out with the error "NameError in SessionsController#create "
I see the problem, which is pretty obvious, but what I don't know is, how do I fix this without regenerating the content? Is there a way to reverse the generation process to clear out all changes made by the generation?
I tried just renaming the files to sessions_controller with e SessionsController class, but that failed.
While writing this, I solved my own problem. I had to rename session to sessions in the routes file as a map.resource and rename the view directory from session to sessions, and update session_path in the html.erb file to sessions_path.
So I solved my problem, but my answer regarding removing generated content still remains. Is it possible to ungenerate content?
Actually, script/destroy works for any generator - generators work by reading a script of sorts on what files to create; script/destroy just reads that script in reverse and removes all the files created, as long as you give it the same arguments you passed to script/generate.
To sum up: script/destroy authenticated user session would have removed all the generated files for you, after which you could have run script/generate user sessions without a problem.
I've never tried script/destroy, but if you're reverting changes that you just made, the generate command should give you a list of files added and changes made. If you're using a version control system of some sort, running status/diff might help as well.
You can just roll back to the previous revision in subversion, and start again, right? right? :-)
rails has script/destroy for 'ungenerating' stuff, but I suspect that will only work for the stuff rails ships with, not the restful authentication plugin.
I'd say your best bet is find-in-files (or grep -R if you're not using an IDE) - find everything that refers to your old SessionController and change it

Resources