How to add additional functions to devise controllers - ruby-on-rails

I'm using Devise for student authentication and I have other actions called show_profile and edit_profile so a student can see and edit his profile.
The problem is the controller I made over writes the Devise controllers so the sign in/up stops working. How can I make my controller an extension for the Devise controllers?
If I put those two:
class Students::RegistrationsController < Devise::RegistrationsController
class StudentsController < ApplicationController
and comment this when logging in class StudentsController < ApplicationController and this class Students::RegistrationsController < Devise::RegistrationsController after login it works.
class Students::RegistrationsController < Devise::RegistrationsController
#class StudentsController < ApplicationController
private
def secure_params
params.require(:student).permit(:name, :father_name, :grand_father_name)
end
public
before_action :authenticate_student!
def show_profile
#student = current_student
end
def edit_profile
#student = current_student
end
def update_profile
#student = current_student
if #student.update_attributes(secure_params)
redirect_to(:action => 'show_profile',:id => #student.id )
flash[:notice] = "student edited successfully"
else
render('edit_profile')
end
end
end

You have to tell Devise that you're using a custom setup in your routes.rb
Something like this, tweak to your needs.
devise_for :users,
controllers: {
registrations: 'student/registrations'
}
Use devise_for :students obviously if that's what your model is called.

Related

Save form data(text field) in database in rails

I have created a user controller with login and logout.
After login user should be able to give some comment in text box input and it should be saved in db.
How to associate the comment to the user. My users controller is
class UsersController < ApplicationController
def new
end
def create
user = User.new(user_params)
if user.save
session[:user_id] = user.id
redirect_to '/url'
else
redirect_to '/signup'
end
end
def user_params
params.require(:user).permit(:name, :email, :password, :password_confirmation)
end
end
my urls controller is
class UrlsController < ApplicationController
def new
end
def create
url = Url.new(url_params)
url.save
redirect_to #url
end
def url_params
params.require(:url).permit(:url)
end
end
I am getting error in url_params. How it should be for a text field?
For example you need to create Comment model
class Comment < ApplicationRecord
belongs_to :user
end
class User < ApplicationRecord
has_many :comments
end
and create CommentsController
class CommentsController < ApplicationController
before_action :set_user
def create
#user.comments.create(comment_params)
redirect_to root_url
end
private
def set_user
#user = User.find(session[:user_id])
end
def comment_params
params.require(:comment).permit(:text)
end
end

Create Pundit Policies to API controller methods

How to create Policies for API-Controller's using Pundit gem?
Api controller path: /app/controllers/api/posts_controller.rb
#posts_controller.rb
class Api::PostsController < ApplicationController
def create
......
end
def update
......
end
def delete
......
end
end
I have Controller for the same and the corresponding Model
controller path: /controllers/posts_controller.rb
#posts_controller.rb
class PostsController < ApplicationController
def create
......
end
def update
......
end
def delete
......
end
end
I have created the policies for posts controller. How to create the same for API's Controller
Pundit is resource-based, not controller-based. When you call authorize and pass it a resource, Pundit cares about the action name and the resource type, but it does not care about the controller name.
Regardless of whether you call from the Api::PostsController:
# /app/controllers/api/posts_controller.rb
class Api::PostsController < ApplicationController
def create
#post = Post.find(params[:post_id])
authorize #post
end
end
or from your original PostsController:
# /app/controllers/posts_controller.rb
class PostsController < ApplicationController
def create
#post = Post.find(params[:post_id])
authorize #post
end
end
So long as #post is a member of the Post class, you can call authorize #post from the controller of a parent or child or a completely unrelated controller, it doesn't matter. In all cases Pundit will go and look for a method called create? within app/policies/post_policy:
# app/policies/post_policy.rb
class PostPolicy < ApplicationPolicy
attr_reader :user, :post
def initialize(user, post)
#user = user
#post = post
end
def create?
user.present?
end
end

How to send users to different paths according to information entered in rails?

My userinfos controller handles user information. As soon as the user signs up, I want them to go to the page that lets them fill out the user information like name, email, gpa, college...Lets just say they leave before completing the form, when they sign in again, I want to check if the user information has been filled out, if not, I want to take them to enter the new information page. What should I do to make that happen? I was told to add this code to the application
class ApplicationController < ActionController::Base
protect_from_forgery with: :exception
def after_sign_in_path_for(resource)
if #userinformation.Userinfo.count.zero?
new_userinfo_path
else
root_path
end
end
def after_sign_up_path_for(resource)
if #userinformation.Userinfo.count.zero?
new_userinfo_path
else
root_path
end
end
end
But it doesn't work. Since "#userinformation" is an instance variable in the userinfos controller, and it's not related to the application controller, it doesn't work. I know the code is wrong in the above controller, but that's the logic I want. If there count of data in the Userinfo model of the particular user is 0, then I want to direct them to the "new_userinfo_path".
My Userinfo controller:
class UserinfosController < ApplicationController
before_action :find_userinfo, only: [:show, :edit, :update, :destroy]
def index
#userinfors = Userinfo.all
#myvideo = Video.all
end
def show
#myvideo = #userinformation.videos.last
end
def new
#userinformation = current_user.userinfos.build
end
def create
#userinformation = current_user.userinfos.build(userinfo_params)
if #userinformation.save
redirect_to userinfo_path(#userinformation)
else
render 'new'
end
end
def edit
end
def update
if #userinformation.update(userinfo_params)
redirect_to userinfo_path(#userinformation)
else
render 'edit'
end
end
def destroy
#userinformation.destroy
redirect_to root_path
end
private
def userinfo_params
params.require(:userinfo).permit(:name, :email, :college, :gpa, :major)
end
def find_userinfo
#userinformation = Userinfo.find(params[:id])
end
end
Userinfo model:
class Userinfo < ActiveRecord::Base
belongs_to :user
has_many :videos, through: :user
def info_complete?
name? && email? && college? && gpa? && major?
end
end
User model:
class User < ActiveRecord::Base
has_many :userinfos
has_many :videos
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
end
Please tell me if you guys need anymore information to understand the question better.
So what I would do is instead of trying to count an instance object, I'd go to the userInfo model and create a method to check this. Would be something like this:
def info_complete?
name? && email? && college? && gpa? && major?
end
So now you've got a method that will return false unless all the fields in userInfo have a value (.e.g the form isn't complete and we should redirect them there).
So now we can go back to after_sign_in_path method and query the resource
class ApplicationController < ActionController::Base
protect_from_forgery with: :exception
def after_sign_in_path_for(resource)
# I'm not too sure how userInfo relates to a user in your app
if resource.userinfo.info_complete?
redirect_to root_path
else
redirect_to new_userinfo_path
end
end
end
Hope this helps.
Use the association between User and Userinfo to check if the user has any user_infos.
class ApplicationController < ActionController::Base
protect_from_forgery with: :exception
def after_sign_in_path_for(resource)
if resource.userinfos.empty?
new_userinfo_path
else
root_path
end
end
end
Why not simply redirect the user in your SignUpController or SignInController actions?
class SignUpController < ApplicationController
// ...
def create
// Sign up... the user probably won't have any userinfos yet.
redirect_to new_userinfo_path
end
// ...
end
class SignInController < ApplicationController
// ...
def create
// Sign up... the user probably won't have any userinfos yet.
if #userinformation.userinfo.count.zero?
redirect_to new_userinfo_path
else
redirect_to root_path
end
end
// ...
end

how to use namespace in gem Pundit

I have 2 controller, 1 for user and 1 for admin.
controllers/articles_controller.rb
class ArticlesController < ActionController::Base
...
def show
#article = Article.find(parmas[:id])
authorize #article
end
...
end
controllers/admin/articles_controller.rb
class Admin::ArticlesController < AdminController
...
def show
#article = Article.find(parmas[:id])
authorize #article
end
...
end
And i have 2 file policy
policies/article_policy.rb
class ArticlePolicy
extend ActiveSupport::Autoload
autoload :Admin
attr_reader :user, :record
def initialize(user, record)
#user = user
#record = record
end
def show?
# allow show for every user.
true
end
end
And one file policies/admin/article_policy.rb
class Admin::ArticlePolicy
attr_reader :user, :record
def initialize(user, record)
#user = user
#record = record
end
def show?
# only show if use have role manager
user.manager?
end
end
but when i use a account user to show articles at /admin/articles/1/. It show normaly, Should is "Access denied".
How to fix this? (I use gem pundit 1.10).
Use the authorize method to pass the namespace as a parameter.
class ArticlesController < ActionController::Base
...
def show
#article = Article.find(parmas[:id])
authorize [:admin, #article]
end
...
end

Multi-form in rails using Wicked Gem and Devise

I am trying to set a multi-form login system using the Wicked gem. I have devise installed up and running correctly, when following these steps:http://railscasts.com/episodes/346-wizard-forms-with-wicked.
I'm not being redirected to the user_step_paths? everything is done as stated in the tutorial but, I'm guessing because I'm using devise i need to do it in a controller inherited by devise? my code is below for the controllers:
users_controller.rb
class UsersController < Devise::RegistrationsController
def new
#user = User.new
end
def create
#user = User.new(params[:sign_up])
if #user.save
session[:user_id] = #user.id
redirect_to user_steps_path
else
redirect_to new_user_registration_path
end
end
end
users_steps_controller.rb
class UserStepsController < ApplicationController
include Wicked::Wizard
steps :education, :social
def show
render_wizard
end
end
routes
get 'pages/home'
devise_for :users, :controllers => { :registrations => 'users'}
resources :user
resources :user_steps
1.Needed a update method in the controller and needed to define user in the show method:
def show
#user = current_user
render_wizard
end
def update
#user = current_user
#user.update_attributes(user_params)
render_wizard #user
end
2.Needed to generate the devise controllers:
rails generate devise:controllers [scope]
3.Update the registration_controller for devise
class Users::RegistrationsController < Devise::RegistrationsController
# before_filter :configure_sign_up_params, only: [:create]
# before_filter :configure_account_update_params, only: [:update]
# GET /resource/sign_up
def new
super
end
# POST /resource
def create
super
end
# GET /resource/edit
# def edit
# super
# end
# PUT /resource
def update
super
end
# The path used after sign up.
def after_sign_up_path_for(resource)
user_steps_path
end
# The path used after sign up for inactive accounts.
def after_inactive_sign_up_path_for(resource)
super(resource)
end
end
4.This controller is invalid, you need to use the generated controllers by devise:
class UsersController < Devise::RegistrationsController

Resources