In my application I have models File & FileAccess. User A can upload files and give access to many other users (by other users asking for access).
My Models:
class File < ActiveRecord::Base
belongs_to :user
has_many :file_accesses
class FileAccess < ActiveRecord::Base
belongs_to :user
belongs_to :file
My FilesController:
class FilesController < ApplicationController
def accepted_users
FileAccess.create(user_id: params[:user_id], file_id: params[:file_id], accept: true)
end
My routes.rb:
get 'i/:user_id/:file_id', to: 'files#accepted_users', as: :file_access_accepted
My View:
= link_to "Give Access", file_access_accepted_path(#file, other_user.id)
Other users can ask for access & user A can select users that they want to give file access to by clicking on Give Access button.
In my FilesController I have a access_file action & view:
class FilesController < ApplicationController
def access_file
redirect_to #file, alert: "You don't have access to this page!" if #file.user != current_user
end
Currently this view/page is only viewable to File owner and if user is not the file owner, they'll be send back with a alert.
How can I achieve it so this page/view is accessible to File owner AND all other users that have been accepted accept: true by the file owner.
Try this one
def access_file
if #file.user != current_user && !#file.file_accesses.map(&:user).include?(current_user)
redirect_to #file, alert: "You don't have access to this page!"
end
end
or
def access_file
if #file.user != current_user && !FileAccess.exists?(file: #file, user: current_user)
redirect_to #file, alert: "You don't have access to this page!"
end
end
The latter should be just one SQL query
Related
I have 3 models of User, Role and UserRole with their respective controllers as UsersController, RolesController and UserRolesController.
I have a method in the UserRoles controller which I would want to access through the Users controller but I keep having errors as explained below.
I have tried various means of even moving the method def self.add_roles_to_user(user, role) from the UsersRoles controller into the UserRole model and call it but I keep having the same error.
I have gone through lots of similar questions and various blogs, including those on this platform such as Calling a method from controller, and others but to no good results.
class UserRole < ApplicationRecord
# many-to-many association using join table with roles and user
belongs_to :user, inverse_of: :user_roles
belongs_to :role, optional: true, inverse_of: :user_roles
end
class User < ApplicationRecord
has_many :user_roles, inverse_of: :user
has_many :roles, through: :user_roles
end
class Role < ApplicationRecord
# table associations between role and user
has_many :user_roles, inverse_of: :role
has_many :users, through: :user_roles
end
class UserRolesController < ApplicationController
def self.add_roles_to_user(user, role)
if ! user.nil?
if role.length > 0
role.each do |sel_role|
#u_role = UserRole.new
#u_role.user_id = user_id
#u_role.role_id = sel_role.role_id
#u_role.save
end
end
end
end
end
class Users::RegistrationsController < Devise::RegistrationsController
def create_user
respond_to do |format|
if #user.save
# add roles
UserRoles.add_user_roles(params[:user], params[:role])
end
end
end
end
I am calling the add_uer_to_role method in the User controller when I am adding or creating a new user.
What I have noticed is that I keep getting different errors based on how I call the method.
For example, I expect to have no errors when I call the method like; UserRoles.add_roles_to_user(params[:user], params[:role]) but it gives the error NameError (uninitialized constant Users::RegistrationsController::UserRoles):
Hoping a good samaritan will come to my aid as soon as possible. Thanks in advance
If it is a common function, you can define it in application controller and call it. Else you can define in helper.
Please verify Calling a method from another controller
You can use that function as a module and use it:
# lib/common_stuff.rb
module CommonStuff
def common_thing
# code
end
end
# app/controllers/my_controller.rb
require 'common_stuff'
class MyController < ApplicationController
include CommonStuff
# has access to common_thing
end
I have a basic authorization class in a Rails application which looks like this:
class Ability
include CanCan::Ability
def initialize(user)
if user
can :access, :rails_admin # only allow admin users to access Rails Admin
can :dashboard
if user.admin?
can :manage, :all
else
can :manage, [Agreement, Attachment, Contact, Deadline, Event, Image, Photo, Project, Submission, Talk]
can :update, User, id: user.id
end
end
# Current user cannot delete his account
cannot :destroy, User, id: user.id
end
end
Now, I get an unauthorized error when trying to access the dashboard with a simple user, but once I put can :manage, :all for a simple user condition it is misteriouslly let through and see the dashboard.
What is :manage, :all having more than :manage, [All_my_tables] and why is my user not let in using this way?
Here is the answer, I just need to to :manage, :all for a simple user and then override the permissions.
class Ability
include CanCan::Ability
def initialize(user)
#Check if the user is logged in
if user
#Grant access to the dashboard
can :access, :rails_admin
can :dashboard
can :manage, :all
#Simple user permissions set here
if !user.admin?
alias_action :create, :update, :destroy, to: :cud
can :manage, :all
cannot :cud, User
cannot :destroy, [Agreement, Submission]
end
end
can :update, User, id: user.id #User can edit his/her own account
cannot :destroy, User, id: user.id #User cannot delete his/her own account
end
end
Thanks for the down votes, but this question has been well researched before coming here
What did I miss?
ERROR: undefined local variable or method `feedback' for #<#<Class:0x007f66dc8dca30>:0x007f66dc8cee80>
Migration:
class CreateFeedbacks < ActiveRecord::Migration
def change
create_table :feedbacks do |t|
t.references :user
t.text :body
t.timestamps
end
end
end
Model:
class Feedback < ActiveRecord::Base
attr_accessible :body, :user
belongs_to :user
end
Controller:
class FeedbacksController < ApplicationController
before_action :authenticate_user!
def index
#feedback = Feedback.all
end
def new
#feedback = Feedback.new
end
def create
#user = User.find(params[:user])
#feedback = #user.feedbacks.create(params[:feedback])
respond_to do |format|
if #feedback.save
format.html { redirect_to #user, notice 'Comment was successfully created.' }
format.json { render json: #feedback, status: :created, location: #feedback }
else
format.html { render action: "new" }
format.json { render json: #feedback.errors, status: :unprocessable_entily }
end
end
end
User model:
has_many :feedback
Routes:
resources :feedbacks
resources :users do
resources :feedbacks
end
Firstly, it helps a lot to style your question and code correctly as well as mark your files (routes.rb, controllers, models correctly). Else it would be very difficult for readers to understand your question and spot issues with your code. You can refer to https://meta.stackoverflow.com/editing-help for the styleguide/ markdown.
Secondly, it looks like your routes.rb are incorrect - but again, this could be due to your formatting. Based on your question, it looks like your routes are:
resources :feedbacks
resources :users do
resources :feedbacks
end
end
When it should be:
resources: users do
resources: feedbacks
end
Thirdly, your seem to have a typo in your model (feedback instead of feedbacks. That is:
class User < ActiveRecord::Base
has_many :feedbacks
end
class Feedback < ActiveRecord::Base
belongs_to :user
end
Lastly, do add specifics and what exactly you ran that caused the error. E.g. did you run something in console, what page did you load?
Using Rails 3.1.3 with Devise 1.5.3. My app has accounts and users. Each account can have multiple users. A user can have one role, "user" or "account_admin". Devise signup routes to accounts#new. The account and an initial account_admin user are created simultaneously. Got this working as described here (although things have evolved some since then).
An account_admin signs should be able to create additional users in that account. That's where I'm running into trouble: instead of creating new users, it's just redirecting to the user_path (users#show) page with the message "You are already signed in." (user_path is my overridden after_sign_in_path.)
This article asks a similar question. The answer suggests a separate namespace for admins, but since admins are part of my regular app I don't think that applies.
I've defined a complete UsersController. According to the log, GET "/users/new" renders from my "UsersController#new". However POST "/users" is intercepted by Devise and rendered from "Devise::RegistrationsController#create".
config/routes.rb
devise_for :users
devise_scope :user do
get "signup", :to => "accounts#new"
get "signin", :to => "devise/sessions#new"
get "signout", :to => "devise/sessions#destroy"
end
resources :users
resources :accounts
app/controllers/users_controller.rb
class UsersController < ApplicationController
before_filter :authenticate_user!
load_and_authorize_resource # CanCan
...
def new
# CanCan: #user = User.new
end
def create
# CanCan: #user = User.new(params[:user])
#user.skip_confirmation! # confirm immediately--don't require email confirmation
if #user.save
flash[:success] = "User added and activated."
redirect_to users_path # list of all users
else
render 'new'
end
end
...
end
I've tried overriding the Devise controller, thinking I could tell it to use my users#create action if the user is already signed in. The log tells me it is using my controller ("Processing by RegistrationsController#create as HTML"), but it doesn't seem to execute its code. I've commented out my custom actions and just left in the logger lines, but I don't get my logging messages. And in spite of super being commented out, the behavior doesn't change--it still redirects with "You are already signed in."
config/routes.rb
devise_for :users, :controllers => {:registrations => "registrations"}
app/controllers/registrations_controller.rb
class RegistrationsController < Devise::RegistrationsController
def new
logger.info "Custom RegistrationsController: new"
super
end
def create
logger.info "Custom RegistrationsController: create"
# super unless user_signed_in?
# render "users#create"
end
def update
super
end
end
What am I missing? How can I let the account_admin user create additional users?
The main issue is that Devise was intercepting the POST "/users" (and a few other routes). Found this workaround to allow my Users controller handle those routes: change the devise_for to skip registrations, then add back in the routes for which Devise normally defines aliases:
routes.rb
devise_for :users, :skip => [:registrations]
devise_scope :user do
get "signup", :to => "accounts#new"
get "signin", :to => "devise/sessions#new"
get "signout", :to => "devise/sessions#destroy"
get "cancel_user_registration", :to => "devise/registrations#cancel"
post "user_registration", :to => "users#create"
get "new_user_registration", :to => "accounts#new"
get "edit_user_registration", :to => "users#edit"
end
resources :users
resources :accounts
Never figured out why the Devise controller override wasn't working.
A user on this thread pointed out the devise_invitable gem which might be an interesting alternative.
This is how I ended up getting this to work with my setup (Devise tied to my User model -- no separate Editor/Admin model):
class UsermakersController < ApplicationController
before_action :authenticate_user!
def new
#user = User.new
end
def create
#user = User.new(user_params)
respond_to do |format|
if #user.save
format.html { redirect_to users_path, notice: 'User was successfully created.' }
format.json { render :show, status: :created, location: #user }
else
format.html { render users_path }
format.json { render json: #user.errors, status: :unprocessable_entity }
end
end
end
private
def user_params
userParams = params.require(:user).permit(:name, :email)
end
end
From here, when you want to add a new User as another User, simply call the Usermakers#new url in your form, e.g., I have this at the bottom of my Users index page:
<%= link_to 'Add User', new_usermaker_path, id: 'new_user_link' %>
And the Usermakers form looks like:
= simple_form_for #user, url: usermakers_path, html: {multipart: true} do |f|
=f.error_notification errors: true
= f.input :name
= f.input :email
%p
= f.button :submit, 'Create User', class: 'button'
Of course, you'd need to add a dummy new.html.erb file which simply renders _form.html.erb to use this.
Just add the new and create methods to your routes.rb file (whether by resources :usermakers, or more specific routes) and you should be good to go. Hope this helps!
I have following controller:
class CarsController < ApplicationController
autocomplete :user, :name
before_filter :require_user, :except => [:my_action]
def index
end
...
def my_action
end
end
I want to allow to see all actions in this controller only for log in users - this works me fine. But the action my_action I would like to have accesible for everyone - also for a people who are not log in.
I tried to set :before_filter with the :except parameter, also with the :only parameter, but nothing works me... The app always want for me to be log in... what I am doing still wrong?
EDIT: require_user from application_controller.rb:
def require_no_user
logger.debug "ApplicationController::require_no_user"
if current_user
#store_location
flash[:warning] = "You must be logged out to access this page"
redirect_to account_url
return false
end
end
Use
skip_before_filter :require_user, :only => [:my_action]