Rails and Devise - Add a Field To Log-In - ruby-on-rails-3

I have set up a blog with secure log-in using the Devise plugin and its working well. I'm going to add an additional 'username' field at sign-up and article posts will then display this info. How do I achieve this so the username goes into the db - any code help would be appreciated?
User names will need to be unique but I will look into this later.

As the Devise wiki sez:
Create a migration
rails generate migration add_username_to_users username:string
Run the migration
rake db:migrate
Modify the User model and add username to attr_accessible
attr_accessible :username
more info here
For uniqueness you could just do a validation on the User model
Hope this helps!

Okay so you have 2 questions in the same topic.
The first one has been answered and you followed these steps: Add custom fields to devise
Then for your next question: the problem isn't the user but #article because this variable is nil. So Rails can't find the User related to something that is nil.
You should post your controller and your _article view so I can help further.
Also I don't understand what you meant by :
I changed the object from 'email' to 'username' to stop it showing the submitters email address in the article
..You can choose whatever you want to display without replacing anything. If you want to display the user's username, just do user.username

add belongs_to :user in your article.rb and has_many :articles to your user.rb
update your migration of article to include a user_id:integer field (or use t.references :user)
update your ArticlesController#create action to use current_user.create_article or build_article
be sure to invoke the authenticate_user! before_filter for the :create action
before_filter :authenticate_user!, only => :only => [:new, :create, :edit, :update, :destroy]
ref:
http://guides.rubyonrails.org/association_basics.html

Related

Rails 4.0 - Nested Attributes with Devise

I am using Rails 4.0 and would like to use Devise for my sign-up/sign-out/etc.
However, on my sign-up page I would like to have fields not only from the user model that devise creates but also another model that users have a relationship with (organizations in this case).
I have setup associations on the models for user and organization like so:
user.rb
has_one :organization
accepts_nested_attributes_for :organization
organization.rb
belongs_to :user
Any ideas on how to make this happen? I tried overriding the registration controller for devise but haven't had any luck.
You need to override the views and insert a fields_for block for that :organization association. Run rails generate devise:views and look for the new view files in your app/views/devise directory.

Creating Users with admin AND registerable

I'm relatively new to ruby on rails, and so I am now very confused how to setup a user management system for admins.
Besides, users should be able to register themselfs (Devise Registerable).
I have a User controller, using devise_for :users and resources :users .
I can sign_up users, since I used the :registerable, flag in my Users model.
What I want to do now is to add the ability for admins to create users.
If I used the described system, I always get the message 'You are already signed in' when creating a new user through /users/new as admin. This is a message from devise.
So I followed the tutorial www.tonyamoyal.com/2010/07/28/rails-authentication-with-devise-and-cancan-customizing-devise-controllers/ to use cancan to restrict some actions and created a own devise registrations controller like described there.
My cancan ability model looks like this:
if user.has_role?(:admin)
#admin
can :manage, :all
elsif !(user.new_record?)
#logged in but no admin
...
else
# Guest
can :create, User
end
and my registrations controller like in the tutorial
class RegistrationsController < Devise::RegistrationsController
before_filter :check_permissions, :only => [:new, :create, :cancel]
skip_before_filter :require_no_authentication
def check_permissions
authorize! :create, resource
end
end
I also added the controller to the routes.rb
With this I can create new users with the admin, but if I want to sign_up as not logged in user ("#Guest") I get always the message cancan exception "Access denied". And if I call exception.subject in the CanCan exception handling it is empty.
Can it be, that 'resource' from my controller is not initialized? How can I get the expected behaviour?
Thanks a lot for your help ;-)
Mhm, I figured out, that resource seems to be a method of the devise-controller.
No idea, why it is not called, or is not returning an object
My solution was now (since I can only register users) to change
def check_permissions
authorize! :create, resource
end
to
def check_permissions
authorize! :create, User #could also be User.new
end
And with this it works. But I'm not sure, if it is the best solution ;-)

Rails application design, user-dependent routing and content

I'm currently building a rails application that contains 3 user types. This is my first experience with web development, and I would like to avoid making crucial design errors that will cost me later on. Hopefully more experienced rails users and web developers will be able to guide me in the right direction.
I want to use Devise as my primary authentication system, and I am currently planning something like this in order to support 3 user-types within the Devise framework:
class User < ActiveRecord::Base
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
attr_accessible :email, :password, :password_confirmation, :remember_me
belongs_to :rolable, :polymorphic => true
end
For each of the three user-types:
# usertype1.rb
class UserType1 < ActiveRecord::Base
has_one :user, :as => :rolable
end
# usertype2.rb
class UserType2 < ActiveRecord::Base
has_one :user, :as => :rolable
end
Essentially, there is a polymorphic association between the user class and the several different user types. My hope is that this approach will allow me to eventually add different associative keywords within the user-type models (such as has-many) that will allow convenient querying of the database.
I'm also concerned about how to implement user-dependent routing. The idea is that each user-type will see a separate "hub" when they log-in, with different dashboards, different actions, etc. I was thinking that I would approach this by overriding the Devise SessionsController. Something like this:
class SessionsController < ApplicationController
def new
end
def create
user = User.find_by_email(params[:email])
if user && user.authenticate(params[:password])
session[:user_id] = user.id
if user.type == 1
redirect_to hub_typeone
else if user.type == 2
redirect_to hub_typetwo
else
redirect_to hub_typethree
else
flash.now.alert = "Email or password is invalid"
render "new"
end
end
def destroy
session[:user_id] = nil
redirect_to root_url, notice: "Logged out!"
end
end
The idea is that upon successful authentication, the user is routed to a different page based on user type. I'm planning on using the devise current_user framework to then query the database to populate the hubs with the user-specific data.
Do you guys have any pointers for me? Do you see any huge flaws in my plans/reasoning/approach? Thanks in advance!
I get a feeling you are over-engineering this, and building something You Aren't Gonna Need It
It's best if you are clear about what the three different user types are. Most applications would require the following three user types:
Guest users, who aren't logged in, and can access some part of the application
Regular users
Admin users who administer the rights of regular users.
I am curious to know what other user types you would need if they are not in this list.
Devise wikipages has suggestions on how to create a guest user, and how to add an admin role. Probably best to start by implementing the functionality of the regular users of your application, and then use the above mentioned resources to add other user types.

Devise_invitable deletes record associated with inviter (User has_one Profile)

I have just added devise_invitable to an app with a working implementation of devise already in place.
The invitation process itself all works fine (email is sent, new user can click link and set password etc).
The problem is that the inviter, a User, has an associated Profile, which is deleted when the inviter hits the 'Send an invitation' button.
Anyone have any idea why the invitation process would nuke an associated object on the inviter? I am going to try to trace this through the devise_invitable code, but it would be good to know if anyone has had this problem before, or knows where in devise's code the problem might lie.
The User:
has_one :profile, :inverse_of => :user, :dependent => :destroy
The Profile
belongs_to :user, :inverse_of => :profile
The error here is because – by default – devise_invitable's after_invite_path_for simply calls after_sign_in_path_for.
However, it does not pass the current user as the resource, which would be the case with a regular sign in.
If you override after_sign_in_path_for assuming it will only be called after a genuine sign in, as I did, this can be confusing.
(In my particular case: what my overridden method did was to look for the resource's associated profile, and if it didn't have one it would make a new one assuming the user is logging in for the first time. When devise_invitable passed an unexpected resource, this new profile object would overwrite the existing association and the :dependent => :destroy callback would be triggered on the old profile object. D'oh!)

how to protect attributes from mass assignement

Hi I have a NOOB question in light of what happend at GITHUB with their application being exploited because of the security hole in Rails.
What is the best way to protect object attributes in Rails but still allow them to be assigned values where applicable?
Thanks
Actually Rails 3.1 has added new built-in ways to handle mass-assignment with roles which is probably something that you want to take a look at.
Release notes here
Basically it works like this:
class User < ActiveRecord::Base
attr_accessible :name
attr_accessible :name, :role, :as => :admin
end
What this enables you to do is that you can use the following way to allow the user to update his own information in one of your controllers:
#user.update_attributes(params[:user])
And that usage can never update the :role attribute in the User model. But when you have your admin users managing the roles in a separate controller, then you can user the following syntax:
#user.update_attributes(params[:user], :as => :admin)
And that will allow the :role attribute to be updated as well