I could not word the title properly but I hope you understand. I have followed the exact example on how to generate a controller.
rails generate devise:controllers users
My routes:
devise_for :users, controllers: { sessions: "users/sessions" }
Then copy (new.html.erb) from devise/sessions to views/users/sessions, then delete the view from devise/sessions/
Then in:
class Users::SessionsController < Devise::SessionsController
def new
super
#foo = 'Bar'
end
end
Now in my views/users/sessions/new.html.erb:
<%= #foo %> # should show Bar
That not showing. Am I missing something?
This is what your SessionsController should look like:
class Users::SessionsController < Devise::SessionsController
def new
#foo = 'bar'
super
end
end
Note how super is below your custom code.
When you call super, it calls the parent method; in our case Devise::SessionsController#new. You need to initialize #foo before calling that method and rendering the new.html.erb.
Related
I want to override show logic in order to permit change password not only if it is expired, but some days earlier. I need to modify or replace this before_filter logic
def skip_password_change
return if !resource.nil? && resource.need_change_password?
redirect_to :root
end
I want to make my controller like this:
class PasswordsController < Devise::PasswordExpiredController
# ...
def skip_password_change
return if !resource.nil? && (resource.need_change_password? || ... )
redirect_to :root
end
end
How to achieve my goal?
UPD:
all answers below are kind of right, I missed one thing - my custom controller was placed inside controllers/admin directory, so I should name it Admin::CustomPasswordExpiredController, but I missed Namespace prefix Admin and rails fell into circular dependency.
Just extend devise controller with your custom controller:
# config/routes.rb
devise_for :users, controllers: { passwords: 'custom_passwords' }
# app/controllers/custom_passwords_controller.rb
class CustomPasswordsController < Devise::PasswordsController
def edit
resource = resource_class.new
return unless resource.need_change_password? # your middleware logic here
super
end
end
More facilities can be found in devise PasswordsController documentation (by clicking "View source")
You can try this workaround, first skip the default before_action for skip_password_change method, then add a custom method to wrap it in a condition. Try this
class PasswordsController < Devise::PasswordExpiredController
skip_before_action :skip_password_change, only: :show
before_action :skip_password_change_show, only: :show
def skip_password_change_show
return if !resource.nil? && (resource.need_change_password? || #yourcondition )
redirect_to :root
end
end
Hope that helps!
Go to your routes file and overwrite the controller methods there.
Something like devise_for :users, controllers: {x: 'y'} where x is the name of the controller from devise that you want to overwrite and y is the name of your custom controller you want to overwrite with
I have DRY'd up the controller code using inheritance.
class MastersController < ApplicationController
def index
...
...
end
...
...
end
class ItemsController < MastersController
end
Now I have added a custom action to the MastersController
class MastersController < ApplicationController
def index
...
...
end
...
...
def clone
...
...
end
end
I have added the routes for item
resources :items do
get :clone
end
Now when I try to access myapp.dev/items/1/clone, I get the error
AbstractController::ActionNotFound at /items/1/clone
The action 'clone' could not be found for ItemsController
If I add the 'clone' action in ItemsController the error goes away.
class ItemsController < MastersController
def clone
...
...
end
end
How do I abstract a custom action in Rails Controller?
You can use it like this
def clone
super
end
in your child Controller
It is not possible to use clone as an action which is inherited from a parent controller. This is true of ApplicationController in addition to your MastersController.
Rename your action to copy and you will be able to define it in MastersController and route correctly to ItemsController#copy.
Please note, I cannot tell you why this is. There is a Ruby method clone which is defined on the Object class. I suspect this is the reason - maybe someone with more knowledge could explain.
I'm a Rails beginner and I learn that I always must try to be more DRY.
I'm have a comment system associated to my content model, and I load my comment with ajax on page scroll.
In my view I have:
%section.article-comments{'data-url' => content_comments_path(#content)}
and in my routes.rb file I have the route
resources :contents, only: :index do
resources :comments, only: :index
end
My comment controller of course is
def index
#content = Content.find(params[:content_id])
#comments = #content.comments
render ...
end
Now I want to add comments also to videos and gallery.
So I need to add a route for every resource and I need a gallery_index and a video_index.
Content, video and gallery index method in comment controlelr are repeated, and I cannot understand how can I be more DRY.
All your controllers presumably inherit from ApplicationController:
class CommentsController < ApplicationController
If you find yourself with a lot of repetition in any of the controller methods you could define it in ApplicationController instead, with maybe some specific processing in each controller.
For example:
class ApplicationController < ActionController::Base
def index
...some common processing...
specific_index_processing
end
private
def specific_index_processing
# empty method; will be overridden by each controller as required
end
end
class CommentsController < ApplicationController
private
def specific_index_processing
...specific procesing for the comments index method...
end
end
And of course, if one of your controllers needs to be completely different from this common approach you can always just override the entire index method.
Playing with Rails and controller inheritance.
I've created a controller called AdminController, with a child class called admin_user_controller placed in /app/controllers/admin/admin_user_controller.rb
This is my routes.rb
namespace :admin do
resources :admin_user # Have the admin manage them here.
end
app/controllers/admin/admin_user_controller.rb
class AdminUserController < AdminController
def index
#users = User.all
end
end
app/controllers/admin_controller.rb
class AdminController < ApplicationController
end
I have a user model which I will want to edit with admin privileges.
When I try to connect to: http://localhost:3000/admin/admin_user/
I receive this error:
superclass mismatch for class AdminUserController
This error shows up if you define two times the same class with different superclasses. Maybe try grepping class AdminUserController in your code so you're sure you're not defining it two times. Chances are there is a conflict with a file generated by Rails.
To complete what #Intrepidd said, you can wrap your class inside a module, so that the AdminUserController class doesn't inherit twice from ApplicationController, so a simple workaround would be :
module Admin
class AdminUserController < AdminController
def index
#users = User.all
end
end
end
I fixed it by creating a "Dashboard" controller and an "index" def. I then edited my routes.rb thusly:
Rails.application.routes.draw do
namespace :admin do
get '', to: 'dashboard#index', as: '/'
resources :posts
end
end
In Rails MVC, can you call a controller's method from a view (as a method could be called call from a helper)? If yes, how?
Here is the answer:
class MyController < ApplicationController
def my_method
# Lots of stuff
end
helper_method :my_method
end
Then, in your view, you can reference it in ERB exactly how you expect with <% or <%=:
<% my_method %>
You possibly want to declare your method as a "helper_method", or alternatively move it to a helper.
What do helper and helper_method do?
make your action helper method using helper_method :your_action_name
class ApplicationController < ActionController::Base
def foo
# your foo logic
end
helper_method :foo
def bar
# your bar logic
end
helper_method :bar
end
Or you can also make all actions as your helper method using: helper :all
class ApplicationController < ActionController::Base
helper :all
def foo
# your foo logic
end
def bar
# your bar logic
end
end
In both cases, you can access foo and bar from all controllers.
Haven't ever tried this, but calling public methods is similar to:
#controller.public_method
and private methods:
#controller.send("private_method", args)
See more details here