I have a controller I created for Devise that I want to use to add a few more pages inside /devise/registration/
class RegistrationsController < Devise::RegistrationsController
skip_before_filter :detect_account_ended
def import
#title = "Import customers from Quickbooks"
end
def categories
#title = "Edit Categories"
#categories = current_user.categories
respond_to do |format|
format.html # index.html.erb
format.json { render json: #categories }
end
end
protected
def after_update_path_for(resource)
edit_user_registration_path
end
end
I created the routes
devise_for :users,
:path_names => {
:sign_up => "register",
:destroy => "logout" },
:controllers => {
:registrations => :registrations } do
get '/users/sign_out' => 'devise/sessions#destroy'
get '/users/import' => 'devise/registrations#import'
get '/users/categories' => 'devise/registrations#categories'
end
And the views. The views show up correctly but the objects I pass from the registrations controller are not going to the views. How do I fix this so that these objects are getting passed to my views?
Try access them directly into view like this:
current_user.categories
As current_user is available in views too, as for the #title, you don't have to pass it as a variable, as you can add the text you need directly into view too.
Related
In migrating a rails application from 3.2 to 4.1, I am hitting some issues with user creation. As there is a need to distinguish the current_user form a local_user. The controller create action
def create
#local_user = User.new(user_params)
respond_to do |format|
if #local_user.save
if params[:user][:avatar].present?
format.html { render :crop }
else
format.html { redirect_to(admin_user_path(#local_user), :notice => 'User was successfully created.') }
end
else
format.html { render :action => "new" }
end
Generates a console error: Unpermitted parameters: name, surname, pen_name[...], yet the User controller defines them:
def user_params
params.require(:user).permit(:name, :surname, :pen_name, [...])
end
The form call is:
<%= form_for(resource, :as => resource_name, :url => registration_path(resource_name), :method => :post, :validate => true) do |f| %>
This is necessarily a devise issue for a user can be created with the scaffolding for the User class with the exact same variables. There is some logic that devise is going through which does not pull all the controller logic ; what am I missing?
Needs a devise specific initializer, as per this demo, where all variables can be entered as an array.
I have a Page Model that has a :name attribute. I have a specific route for the Page Model with the name "home", because I want this specific Page record to be found at the root_url. This works.. but because I'm hard coding the route... I only want users with the role "super_admin" to be able to change the :name attribute, on the Page model, where the name == "home". For example, users with the "admin" role should not be able to change the :name attribute on the "home" Page.
Can I get that fine grained with CanCan?
Should I put this logic in the PageControllers update action?
Should I set the "page#show" route differently (not hard code it)?
Not sure how to do any of these.
Thanks in advance for any advice!
ability.rb
elsif user.role == "admin"
can :manage, :all
cannot :update, Page, ["name == ?", "home"] do |page|
page.name == "home"
end
end
routes.rb (I'm using friendly_id to generate a slug from the :name attribute)
match '/:slug', :to => "pages#show", :as => :slug, :via => :get
root :to => 'pages', :controllers => "pages", :action => "show", :slug => "home"
pages_controller.rb (standard)
def update
#page = Page.find(params[:id])
respond_to do |format|
if #page.update_attributes(params[:page])
format.html { redirect_to #page, notice: 'Page was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: "edit" }
format.json { render json: #page.errors, status: :unprocessable_entity }
end
end
end
I must admit, I've read your question three times, and I think I have answers for you...
1 - Yes, I believe so. However, I'm not convinced your ability.rb code is correct. I'd aim for something closer to this:
cannot :update, Page do |page|
page.name == "home"
end
2 - If you do load_and_authorize_resource in your controller, that should be all you need, because that will load #page for you.
class PagesController < ApplicationController
load_and_authorize_resource
def update
respond_to do |format|
if #page.update_attributes(params[:page])
format.html { redirect_to #page, notice: 'Page was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: "edit" }
format.json { render json: #page.errors, status: :unprocessable_entity }
end
end
end
end
3 - To me, your route looks fine. That's likely the way I'd approach it.
I use Devise and I want to do my logout action.
What I want to do is, that when I log out, I want to create a own JSON object to return. At this time, after I logt out, I get all my root articles.
How can I write my own destory action like I have found the create action?
class SessionsController < Devise::SessionsController
def create
resource = warden.authenticate!(:scope => resource_name, :recall => :failure)
return sign_in_and_redirect(resource_name, resource)
end
def sign_in_and_redirect(resource_or_scope, resource=nil)
scope = Devise::Mapping.find_scope!(resource_or_scope)
resource ||= resource_or_scope
sign_in(scope, resource) unless warden.user(scope) == resource
return render :json => {:success => true, :redirect => stored_location_for(scope) || after_sign_in_path_for(resource)}
end
def failure
return render:json => {:success => false, :errors => ["Login failed."]}
end
end
And my Routes in routes.rb
devise_for :users, :controllers => {:session => "sessions"} do
get "/users/sing_out" => "devise/sessions#destroy"
end
this is the destroy method of the sessions-controller.
you should be able to customize it to your needs. i think that it would be wiser to add another action and implementing your custom behavior there, as this will be less likely to cause unexpected errors with upgrading devise in the future.
# DELETE /resource/sign_out
def destroy
redirect_path = after_sign_out_path_for(resource_name)
signed_out = (Devise.sign_out_all_scopes ? sign_out : sign_out(resource_name))
set_flash_message :notice, :signed_out if signed_out
# We actually need to hardcode this as Rails default responder doesn't
# support returning empty response on GET request
respond_to do |format|
format.any(*navigational_formats) { redirect_to redirect_path }
format.all do
method = "to_#{request_format}"
text = {}.respond_to?(method) ? {}.send(method) : ""
render :text => text, :status => :ok
end
end
end
I have the following code in one of my controllers (in a Rails 3.1 application) which works well:
def index
##calls = Call.all
#calls = Call.where(:destination => '12345678').limit(25)
respond_to do |format|
format.html # index.html.erb
format.json { render :json => #calls }
end
end
I'm trying to work out the best way of proceeding from here, basically each user has their own destination code (in this case it's 12345678).
Is it possible for the users to have a value in a model which can be passed into the controller?
An example
def index
##calls = Call.all
#calls = Call.where(:destination => '<% #user.destination %>').limit(25)
respond_to do |format|
format.html # index.html.erb
format.json { render :json => #calls }
end
end
I realise that the above code wouldn't work but what would be a workaround to achieve the same thing?
Update with a little more information:
I have two models, one is calls and the other is users.
I want to be able to do something like this:
#calls = Call.where(:destination => #user.destination_id).limit(25)'
Where :destination is part of the Calls model and destination_id is part of the users model. Each user has a different destination_id value.
Routes
Outofhours::Application.routes.draw do
ActiveAdmin.routes(self)
devise_for :admin_users, ActiveAdmin::Devise.config
get "log_out" => "sessions#destroy", :as => "log_out"
get "log_in" => "sessions#new", :as => "log_in"
get "sign_up" => "users#new", :as => "sign_up"
resources :users
resources :sessions
resources :calls
root :to => 'dashboards#index'
resources :dashboards
end
user model
class User < ActiveRecord::Base
attr_accessible :email, :company, :destination_id, :password, :password_confirmation
attr_accessor :password
before_save :encrypt_password
validates_confirmation_of :password
validates_presence_of :password, :on => :create
validates_presence_of :email
validates_uniqueness_of :email
validates_uniqueness_of :company
validates_uniqueness_of :destination_id
def self.authenticate(email, password)
user = find_by_email(email)
if user && user.password_hash == BCrypt::Engine.hash_secret(password, user.password_salt)
user
else
nil
end
end
def encrypt_password
if password.present?
self.password_salt = BCrypt::Engine.generate_salt
self.password_hash = BCrypt::Engine.hash_secret(password, password_salt)
end
end
end
call model
class Call < ActiveRecord::Base
end
You could pass the destination to the controller in the params array. This way you could access it in the controller like this
def index
##calls = Call.all
#calls = Call.where(:destination => current_user.destination_id).limit(25)
respond_to do |format|
format.html # index.html.erb
format.json { render :json => #calls }
end
end
Having some trouble with some nested resources routing. What I'm trying to do is link to a user's profile page for editing purposes. In my view it is written as:
<%= link_to "Edit Profile", edit_user_profile_path(current_user) %>
Which errors out with:
No route matches {:action=>"edit", :controller=>"profiles", :user_id=>#<User id: 1, email: "EDITEDOUT", hashed_password: "EDITEDOUT", created_at: "2011-01-20 18:30:44", updated_at: "2011-01-20 18:30:44">}
In my routes.rb file, it looks like so:
resources :users do
resources :profiles, :controller => "profiles"
end
I checked my Rake routes, and it gave me this as a valid option:
edit_user_profile GET /users/:user_id/profiles/:id/edit(.:format) {:action=>"edit", :controller=>"profiles"}
Which I am able to manually navigate to. For good measures, here's proof of my controller:
class ProfilesController < ApplicationController
def edit
#user = current_user
#profile = current_user.profile
end
def update
#user = current_user
#profile = current_user.profile
respond_to do |format|
if #profile.update_attributes(params[:profile])
format.html { redirect_to(orders_path, :notice => "Your profile has been updated.") }
format.xml { head :ok }
else
format.html { render :action => "edit" }
format.xml { render :xml => #profile.errors, :status => :unprocessable_entity }
end
end
end
end
Anyway, I've been having some problem tracking this down. Any pointers would help. For my DB design Profiles belong to Users in a one-to-one relationship. I'm hoping it's just something newbish I'm not noticing a new set of eyes might help.
If you look closely at your route, you'll see that it expects both a :user_id and an :id. The latter, in this case, refers to the user profile.
In order to tell Rails that you want that particular profile, you'll have to specify both the user and the profile in your link, like this:
edit_user_profile_path(current_user, #profile)
Now, Rails will use the first argument (current_user) for the :user_id part of the route, and the second argument (#profile) for the :id.