Access session in Helper file ? Rails 3 - ruby-on-rails-3

how to get session in helper file?
UserHelper.rb
module UsersHelper
def self.auth login, password
user = Users.where("firstname = :firstname AND password = :password", {:firstname => login, :password => password})
if user != []
return true
else
return false
end
end
def self.is_auth? level
puts #session
user = Users.where("firstname = :firstname AND password = :password", {:firstname => #session[:firstname], :password => #session[:password]})
if user != []
return true
else
return false
end
end
end
Admin_controller.rb
class AdminController < ApplicationController
include Rails.application.routes.url_helpers
def initialization
#session = session
end
def index
#session = session
if UsersHelper.is_auth?(2)
render :text => "ssssss"
end
end
def auth
if params[:send] != nil
if UsersHelper.auth params[:firstname], params[:password]
session[:firstname] = params[:firstname]
session[:password] = params[:password]
redirect_to :action => "index"
else
#error = 1
end
end
end
def exit
session.delete(:firstname)
session.delete(:password)
render :json => session
end
end
Error
undefined method `[]' for nil:NilClass
app/helpers/users_helper.rb:13:in `is_auth?'
app/controllers/admin_controller.rb:8:in `index'

Only Controller can access session.
So, in a nutshell, if you are going to use this method in Controllers only like what is you case, you can define it as ApplicationController's method. Or define it a module and include it in AppplicationController.
class ApplicationController < ActionController::Base
def auth
end
def is_auth?
end
end
If you want to use the method in both controller and view, just declare them as helper_method
class ApplicationController < ActionController::Base
helper_method :auth, :is_auth?
def auth
end
def is_auth?
end
end
Ref: http://apidock.com/rails/ActionController/Helpers/ClassMethods/helper_method
Another note: In my opinion it's really not worth the time to build auth system from scratch by yourself. The functionalities are not easy but quite general. There are well baked gems such as Devise, Authlogic. Better to use them.

Related

Allow non registered users to view content with pundit

I have having trouble allowing non-registered/non-logged in users to view the index and show pages for a blog section. I am using Pundit for authorization and realize that at the moment I have my policies set to not allow non-users to view any part of the blog section, but I have no idea how to work around that to have no policy for the index and show page.
My goal is to have the following:
Allow Admin and Editors to view, create, edit, and delete blogs
This portion works pefect
Allow registered users to view blogs
This portion works perfect
Allow non-registered/non-logged in users to view blogs
This part does not work
When I try to view the index page as a non-registered/non-logged in user, I will get an access denied flash message that comes out of my application controller, which is doing what it is supposed to be doing given the current policies.
So my question is: How do I modify my policies to allow non-registered/non-logged in users to view the index and show pages only?
Application Controller
class ApplicationController < ActionController::Base
include Pundit
rescue_from Pundit::NotAuthorizedError, with: :user_not_authorized
# Prevent CSRF attacks by raising an exception.
# For APIs, you may want to use :null_session instead.
protect_from_forgery with: :exception
before_filter :configure_permitted_parameters, if: :devise_controller?
private
def user_not_authorized(exception)
flash[:danger] = "Access denied. You are not authorized to view that page."
redirect_to (request.referrer || root_path)
end
protected
def configure_permitted_parameters
devise_parameter_sanitizer.permit(:sign_up) { |u| u.permit(:username, :email, :password, :password_confirmation, :remember_me) }
devise_parameter_sanitizer.permit(:sign_in) { |u| u.permit(:username, :email, :password, :remember_me) }
devise_parameter_sanitizer.permit(:account_update) {|u| u.permit(:username, :email, :password, :password_confirmation, :current_password)}
end
end
Application Policy
class ApplicationPolicy
attr_reader :user, :record
def initialize(user, record)
raise Pundit::NotAuthorizedError, "You must be logged in to perform this action" unless user
#user = user
#record = record
end
def index?
true
end
def show?
scope.where(:id => record.id).exists?
end
def create?
false
end
def new?
create?
end
def update?
false
end
def edit?
update?
end
def destroy?
false
end
def scope
Pundit.policy_scope!(user, record.class)
end
class Scope
attr_reader :user, :scope
def initialize(user, scope)
#user = user
#scope = scope
end
def resolve
scope
end
end
end
Post Policy
class PostPolicy < ApplicationPolicy
attr_reader :post
class Scope < Scope
def resolve
if user&.admin?&.editor?&.user?
scope.all
else user != admin? || editor? || user?
scope
end
end
end
def permitted_attributes
if user.admin? || user.editor?
[:title, :body, :image, :permalink, :description, :tag_list, :username]
else
[:title, :body, :image, :username]
end
end
def index?
true
end
def show?
true
end
def new?
user.admin? || user.editor?
end
def create?
user.admin? || user.editor?
end
def update?
user.admin? || user.editor?
end
def destroy?
user.admin? || user.editor?
end
end
Post Controller
class PostsController < ApplicationController
before_action :set_post, only: [:show, :edit, :update, :destroy]
after_action :verify_authorized, only: [:destroy]
def index
#meta_title = "Blog"
#meta_description = "page description here"
#posts = Post.all.order("created_at DESC").paginate(:page => params[:page], :per_page => 4)
end
def show
#meta_title = #post.title
#meta_description = #post.description
end
def new
#meta_title = "Add New Blog"
#meta_description ="Add a new blog."
#post = Post.new
authorize #post
end
def edit
#meta_title = "Edit Blog"
#meta_description ="Edit an existing blog."
authorize #post
end
def create
#post = Post.new
#post.update_attributes(permitted_attributes(#post))
#post.user = current_user if user_signed_in?
authorize #post
if #post.save
redirect_to #post, notice: 'Post was successfully created.'
else
render :new
end
end
def update
#post = Post.find(params[:id])
if #post.update_attributes(permitted_attributes(#post))
authorize #post
redirect_to #post, notice: 'Post was successfully updated.'
else
render :edit
end
end
def destroy
if #post.present?
#post.destroy
authorize #post
else
skip_authorization
end
redirect_to posts_url, notice: 'Post was successfully deleted.'
end
private
# Use callbacks to share common setup or constraints between actions.
def set_post
#post = Post.find(params[:id])
end
# Only allow the white list through.
def post_params
params.require(:post).permit(policy(#post).permitted_attributes)
end
end
I've seen a similar question asked Pundit policy_scoper error, but the solution suggested there does not seem to work in my case.
After much frustration, I was finally able to solve the issue. Big thanks go out to #Scott for helping get the controller and testing set up as they should be, and nearly getting the policies working.
Turns out that the raise Pundit::NotAuthorizedError, "must be logged in" unless user in the initializer section of the Application Policy was not allowing non-logged-in users from accessing the index page (just like it's supposed to when you want a closed system...). Since my application is open for anyone to view in the index and show pages of the blog, I needed to remove that line.
Once removed the application would then throw a undefined method admin?' for nil:NilClass for non-logged-in users trying to access the blog index page. This was solved by using the correct conventions of identifying users in Post Policy. For each def in the policy I had user.admin? || user.editor?. That needed to be changed to user&.admin? || user&.editor?.
The code ended up as follows:
Application Policy
class ApplicationPolicy
attr_reader :user, :record
def initialize(user, record)
#user = user
#record = record
end
def index?
false
end
def show?
scope.where(:id => record.id).exists?
end
def create?
false
end
def new?
create?
end
def update?
false
end
def edit?
update?
end
def destroy?
false
end
def scope
Pundit.policy_scope!(user, record.class)
end
class Scope
attr_reader :user, :scope
def initialize(user, scope)
#user = user
#scope = scope
end
def resolve
scope
end
end
end
Post Policy
class PostPolicy < ApplicationPolicy
attr_reader :post
class Scope < Scope
def resolve
if user&.admin? || user&.editor?
scope.all
else
end
end
end
def permitted_attributes
if user.admin? || user.editor?
[:title, :body, :image, :permalink, :description, :tag_list, :username]
else
[:title, :body, :image, :username]
end
end
def index?
true
end
def show?
true
end
def new?
admin_or_editor
end
def create?
admin_or_editor
end
def update?
admin_or_editor
end
def destroy?
admin_or_editor
end
private
def admin_or_editor
user&.admin? || user&.editor?
end
end
Post Controller
class PostsController < ApplicationController
before_action :set_post, only: [:show, :edit, :update, :destroy]
before_action :authenticate_user!, except: [:index, :show]
after_action :verify_authorized, except: [:index, :show]
def index
#meta_title = "Blog"
#meta_description = "blog description"
#posts = Post.all.order("created_at DESC").paginate(:page => params[:page], :per_page => 4)
end
def show
#meta_title = #post.title
#meta_description = #post.description
end
def new
#meta_title = "Add New Blog"
#meta_description ="Add a new blog."
#post = Post.new
authorize #post
end
def edit
#meta_title = "Edit Blog"
#meta_description ="Edit an existing blog."
authorize #post
end
def create
#post = Post.new
#post.update_attributes(permitted_attributes(#post))
#post.user = current_user if user_signed_in?
authorize #post
if #post.save
redirect_to #post, notice: 'Post was successfully created.'
else
render :new
end
end
def update
#post = Post.find(params[:id])
authorize #post
if #post.update_attributes(permitted_attributes(#post))
redirect_to #post, notice: 'Post was successfully updated.'
else
render :edit
end
end
def destroy
if #post.present?
#post.destroy
authorize #post
else
skip_authorization
end
redirect_to posts_url, notice: 'Post was successfully deleted.'
end
private
# Use callbacks to share common setup or constraints between actions.
def set_post
#post = Post.find(params[:id])
end
# Only allow the white list through.
def post_params
params.require(:post).permit(policy(#post).permitted_attributes)
end
end

Rails 4 and Devise - User registration via JSON API

I'm attempting to register a devise user via JSON but keep getting an ActiveModel::ForbiddenAttributesError
class Api::V1::RegistrationsController < ApplicationController
skip_before_filter :verify_authenticity_token
respond_to :json
def create
user = User.new(params[:user])
if user.save
render :json => user.as_json(:auth_token=>user.authentication_token, :email=>user.email), :status=>201
return
else
warden.custom_failure!
render :json => user.errors, :status=>422
end
end
def user_params
params.require(:user).permit(:email, :password)
end
end
Here's my JSON request:
Processing by Api::V1::RegistrationsController#create as JSON
Parameters: {"user"=>{"email"=>"jayson#jayson.com", "password"=>"[FILTERED]"}, "registration"=>{"user"=>{"email"=>"jayson#jayson.com", "password"=>"[FILTERED]"}}}
I realize this has something to do with Strong Parameters but haven't been able to crack it yet.
I would change:
user = User.new(params[:user])
with:
user = User.new(user_params)
From docs:
# This will raise an ActiveModel::ForbiddenAttributes exception because it's using mass assignment
# without an explicit permit step.
def create
Person.create(params[:person])
end

How do I emulate logging in for controller tests?

I have a SearchesController that requires a user to be logged in before it will do its thing.
I'd like to write an rspec helper function login to emulate logging in for controller tests. (NB: I will handle integration / requests specs separately.) My attempts so haven't worked: the logged_in? method in ApplicationController returns false.
The question: how do I write the 'login' helper?
Here's the RSpec controller test:
# file: spec/controllers/searches_controller_spec.rb
require 'spec_helper'
require 'controllers_helper'
describe SearchesController do
include ControllersHelper
describe "GET index" do
it 'without login renders login page' do
get :index
response.should redirect_to(login_path)
end
it 'with login finds searches belonging to user' do
me = FactoryGirl.create(:user)
my_searches = FactoryGirl.create_list(:search, 2, :user => me)
not_me = FactoryGirl.create(:user)
not_my_searches = FactoryGirl.create_list(:search, 2, :user => not_me)
login(me) # want to define this in spec/controllers_helper.rb
get :index
assigns(:searches).should =~ my_searches
end
end
end
Here's the Controller:
# file: app/controllers/searches_controller.rb
class SearchesController < ApplicationController
def index
unless logged_in?
redirect_to login_path, :alert => "You must be logged in to access this page."
else
#searches = Search.where(:user_id => current_user.id)
respond_to do |format|
format.html
format.json { render json: #searches }
end
end
end
end
And here's the ApplicationController code. Note that current_user = x has the effect of logging x in, and it's rather simple: it sets #current_user and session[:user_id].
# file: app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
protect_from_forgery
force_ssl
protected
def current_user
#current_user ||= User.find_by_id(session[:user_id])
end
def current_user=(user)
#current_user = user
session[:user_id] = user && user.id
end
def logged_in?
!!#current_user
end
def require_login
unless logged_in?
redirect_to login_path, :alert => "You must be logged in to access this page."
end
end
helper_method :current_user, :logged_in?, :require_login
end
I may have said this before, but if Stack Overflow gave badges answering one's own questions, I'd have a LOT of badges! :)
Okay, to answer this question you need to look at the documentation for ActionController::TestCase. When you do so, you'll find that it sets up bindings for:
#controller
#request
#response
So for the specific controller given in the OP, writing the login method is trivial:
# file: spec/controllers_helper.rb
module ControllersHelper
def login(user)
#controller.send(:current_user=, user)
end
end
(Did I hear someone say RTFM again? I thought so...)

Devise: How to customize the registrations controller destroy method

I have my user and profiles in separate models. When a user is deleted the linked profile remains, which is the desired result. what I would like to do is flag the profile record as deleted.
I have added a deleted column(boolean) to my profile table, but can't figure out how I can add the set to true set to the devise destroy method?
app\controller\registrations_controller.rb
class RegistrationsController < Devise::RegistrationsController
def destroy
delete_profile(params)
end
private
def delete_profile(params)
profile = Profile.find(params[:id])
profile.deleted = true
end
end
but I can figure out how to get around this error
Couldn't find Profile without an ID
how can I pass in the correct params from the delete user in my views?
Devise doesn't use a params[:id] to destroy the current user (so it isn't provided through the route), but instead uses the current_user.
Here are the relevant parts of the controller:
class Devise::RegistrationsController < DeviseController
prepend_before_filter :authenticate_scope!, :only => [:edit, :update, :destroy]
def destroy
resource.destroy
Devise.sign_out_all_scopes ? sign_out : sign_out(resource_name)
set_flash_message :notice, :destroyed if is_navigational_format?
respond_with_navigational(resource){ redirect_to after_sign_out_path_for(resource_name) }
end
protected
def authenticate_scope!
send(:"authenticate_#{resource_name}!", :force => true)
self.resource = send(:"current_#{resource_name}")
end
end
So your alternative would be to do something like
class RegistrationsController < Devise::RegistrationsController
def destroy
current_user.deleted = true
current_user.save
#some more stuff
end
end

How to create current user method without using any gem or plugin?

i know it's a silly one but i want to know how can we create a current_user method to get access throughout the app without using any gem or plugin ? To test it i created an app that make a user able to share files and folders.How to create such method that a user can only access his folder and files?Here is my code sample:
Login controller:
class LoginController < ApplicationController
layout 'signup'
#to skip checking the authentication and authorization.
skip_before_filter :check_authentication, :check_authorization
def index
end
def authenticate
if request.post?
user = User.authenticate(params[:username],params[:password])
if user
session[:current_user_id]=user.id
session[:name]= user.first_name
puts "session name #{session[:name]}"
redirect_to(:subdomain => user.company.subdomain, :controller => :dashboard)
else
flash.now[:notice] = "Invalid user/password combination"
end
end
end
def destroy
session[:current_user_id] = nil
reset_session
flash[:notice] = "You have been successfully logged out."
redirect_to root_url
end
end
User model:
require 'digest/sha1'
class User < ActiveRecord::Base
#sharering method start
after_create :check_and_assign_shared_ids_to_shared_folders
#this is to make sure the new user ,of which the email addresses already used to share folders by others, to have access to those folders
def check_and_assign_shared_ids_to_shared_folders
#First checking if the new user's email exists in any of ShareFolder records
shared_folders_with_same_email = SharedFolder.find_all_by_shared_email(self.email)
if shared_folders_with_same_email
#loop and update the shared user id with this new user id
shared_folders_with_same_email.each do |shared_folder|
shared_folder.shared_user_id = self.id
shared_folder.save
end
end
end
#to check if a user has acess to this specific folder
def has_share_access?(folder)
#has share access if the folder is one of one of his own
return true if self.folders.include?(folder)
#has share access if the folder is one of the shared_folders_by_others
return true if self.shared_folders_by_others.include?(folder)
#for checking sub folders under one of the being_shared_folders
return_value = false
folder.ancestors.each do |ancestor_folder|
return_value = self.being_shared_folders.include?(ancestor_folder)
if return_value #if it's true
return true
end
end
return false
end
#sharing method end
def self.authenticate(name, password)
user = self.find_by_username(name)
if user
expected_password = encrypt_password(password, user.salt)
if user.hashed_password != expected_password
user = nil
end
end
user
end
#'password' is a virtual attribute
def password
#password
end
def password= (pwd)
#password =pwd
return if pwd.blank?
create_new_salt
self.hashed_password = User.encrypt_password( self.password, self.salt)
end
def self.users_in_company(user_id)
User.find(user_id).company.users
end
private
def password_non_blank
errors.add(:password, "Missing password, please enter your password") if hashed_password.blank?
end
def create_new_salt
self.salt = self.object_id.to_s + rand.to_s
end
def self.encrypt_password(password, salt)
string_to_hash = password +"prftnxt" + salt
Digest::SHA1.hexdigest(string_to_hash)
end
end
i want to access all files as "current_user.files" is it possible without any gem?
Application helper:
module ApplicationHelper
#for current user to use through out the app
def current_user
#current_user ||= session[:current_user_id] && User.find_by_id(session[:current_user_id]) # Use find_by_id to get nil instead of an error if user doesn't exist
end
end
Application controller:
class ApplicationController < ActionController::Base
include UrlHelper
#include ApplicationHelper
helper_method :current_user #make this method available in views
protect_from_forgery
# def current_user
# #current_user ||= session[:current_user_id] && User.find_by_id(session[:current_user_id]) # Use find_by_id to get nil instead of an error if user doesn't exist
# end
end
and in task controller:
class TasksController < ApplicationController
# GET /tasks
# GET /tasks.xml
def index
#menu = "Timesheet"
#page_name = "Manage Task"
company_id = Company.find_by_subdomain(request.subdomain)
#users = User.find_all_by_company_id(company_id)
#tasks = current_user.tasks.all#Task.all
#task = Task.new
respond_to do |format|
format.html # index.html.erb
format.html # new.html.erb
format.xml { render :xml => #tasks }
end
end
end
and my error message i got:
NameError in TasksController#index
undefined local variable or method `current_user' for #<TasksController:0xfa7e638>
that's not so hard ;) just define the method you need:
class ApplicationController < ...
def current_user
#current_user ||= session[:current_user_id] && User.find_by_id(session[:current_user_id]) # Use find_by_id to get nil instead of an error if user doesn't exist
end
helper_method :current_user #make this method available in views
end
Hi friends i have found the way to create current_user method without using any gem or plugin:
In my application_helper.rb i did this :
module ApplicationHelper
def current_user
User.find(session[:current_user_id])
end
end
and at the end in my application controller.rb i called this, because from here i can access it through the application:
class ApplicationController < ActionController::Base
include UrlHelper
include ApplicationHelper
helper_method :current_user
end
and now i can access any data related to current user:
like :
#tasks = current_user.tasks
Thanks to all my friends for their valuable answers.