Troubleshooting two-step nested model signup process - ruby-on-rails-3

I want to initiate a sign-up process on my homepage. In the end, the process ideally would follow the following logic:
user = User.new
user.email = ""
user.password = ""
user.profile = Profile.new
user.profile.info = ""
user.profile.save
user.save
I'll be using nested model forms, of course. But is there a way to spread this into two parts? In part 1 the User would enter mainly user information, as well as a bit of profile information, and part 2 would contain solely 'profile' information. Then when all is said and done the user gets redirected to their user profile.
If this is possible, what is the general thinking on this type of process? Second, I'm wondering if someone can help me figure out how to achieve it. I have the nested model forms all set up but there must be something messed up in my routes.rb file/Controllers that is denying me the experience.
Here's my routes.rb file.
get "profiles/show"
get "/profiles/:id" => "profiles#show", :as => "profile"
post "/signup" => "profiles#create", :as => "signup"
get "skip/signup", :to => "users#newskip"
match "skip/profiles/new", :to => "profiles#newskip"
root :to => "users#new"
And here are my UsersController and ProfilesController respectively:
*class UsersController < ApplicationController*
before_filter :authenticate, :only => [:edit, :update]
def new
#user = User.new
end
def create
#user = User.new(params[:user])
if #user.save
redirect_to signup_path, :notice => 'User successfully added.'
else
render :action => 'new'
end
end
*class ProfilesController < ApplicationController*
before_filter :authenticate, :only => [:edit, :update]
def new
#user.profile = Profile.new
end
def create
#profile = Profile.new(params[:profile])
if #profile.save
redirect_to profile_path(#profile), :notice => 'User successfully added.'
else
render :action => 'new'
end
end
Can anyone help show me the light? I know Devise is a solution but I'm trying to learn without that. At least at first. This previous question/answer looks like a potential starter.

Here is a Railscast about multistep forms. I think it should put you on track for what you're trying to accomplish.

I completed this by having user and profile create on the homepage, Profiles#edit as the second step, with a redirect_to profile.

Related

Rspec controller error? expecting <"index"> but rendering with <""> or it's working?

I'm new with rspec test and maybe there are something that I dont undertand.
if can any help me, I really appreciate some help.
File Structure:
app/models/booking.rb
app/models/user.rb
app/models/role.rb
app/models/ability.rb
app/controllers/bookings_controller.rb
app/views/bookings/index.html.erb
app/views/dashboard/index.html.erb
app/spec/controllers/bookings_controller_spec.rb
I read this link with a similar problem but it isn't solved
Rspec controller error expecting <"index"> but rendering with <"">
is similar, because if I change this line:
it 'should not render index template from bookings' do
get :index
=> response.should_not render_template(:index)
end
for this other:
it 'should not render index template from bookings' do
get :index
=> response.should render_template(:index)
end
I get the same mistake that in the link
expecting <"index"> but rendering with <"">
and I don't know why?
Here's my Code:
My Spec:
describe BookingsController do
context 'as guest' do
before(:each) do
#user = User.new(:email => 'mail_admin#test.com',
:username => 'admin',
:password => 'password_admin',
:password_confirmation => 'password_admin')
#user.save
#when i save, with gem CanCan i assign a default role to #user
#with the default role the user only can see the views/dashboard/index.html.erb
end
it 'should not render index template from bookings' do
get :index
response.should_not render_template(:index)
end
end
end
Controller:
class BookingsController < ApplicationController
load_and_authorize_resource
def index
...
end
def show
...
end
end
My model:
class Booking < Activerecord::Base
paginates_per 20
def
...
end
def
...
end
end
User:
Class User < ActiveRecord::Base
after_save :set_default_role
rolify
.
.
.
.
def set_default_role
self.add_role :default
end
end
Role:
class Role < ActiveRecord::Base
ROLES = {"admin" => "Admin", "default" => "Default"}
.
.
.
.
scopify
end
Ability:
class Ability
include CanCan::Ability
def initialize(user)
user ||= User.new
if user.has_role? :admin
can :manage, :all
elsif user.has_role? :data_consistency
can :read, Booking
end
end
end
CanCan authorizes model access not controller actions. For most other actions these two are more or less the same thing, but not for the index. On the index action CanCan adds a scope to the query for records that includes your authorization restrictions.
What this means is that your guest user will simply not be able to see any records, but the view will still render.
What you want is authentication (ie Devise) and use it from a before_filter in each controller that requires an authenticated user to access.
class BookingsController < ApplicationController
load_and_authorize_resource # Handles authorization
before_filter !authenticate_user # Handles authentication (included with Devise)
...
end
In my case, the problem was solved in before(:each) block!
My code works like this:
before :each do
#user = User.new(:email => 'mail_admin#test.com',
:username => 'admin',
:password => 'password_admin',
:password_confirmation => 'password_admin')
#user.confirm!
sign_in #user
end

Rails 3 Correctly routing the destroy action for a session

I am refactoring my access_controller into a sessions_controller and can't seem to get my destroy action working properly.
Logging in seems to work fine, but I am unable to log out of a session. Here is the link I have for logging out:
<%= link_to("Logout", :controller => "sessions", :action => 'destroy') %>
routes.rb
resources :sessions
sessions_controller.rb
class SessionsController < ApplicationController
def new
end
def create
...
end
def destroy
session[:user_id] = nil
flash[:notice] = "You are now logged out"
redirect_to root_url
end
end
When I click "Logout" I get redirected to "/sessions/destroy" with a message of "The action 'show' could not be found for SessionsController". The destroy actions seems to want an id, but I don't need to pass in an id, I just want to run the action.
Ah, I found the answer here: http://railscasts.com/episodes/250-authentication-from-scratch
I need to set up my routes as follows:
get "log_out" => "sessions#destroy", :as => "log_out"
get "log_in" => "sessions#new", :as => "log_in"
resources :sessions

How can I add a custom column in authlogic?

I've created a simple user system with authlogic using Rails 3. I want to add an "account_type" column to the database. How can I populate this column in the database when the user signs up? I have very very little experience with Rails.
Update: So I know somewhere in "#user = User.new(params[:user])" I need to add :account_type = "user". What's the right syntax for this though?
Here's what I have in my user controller:
class UserController < ApplicationController
before_filter :require_no_user, :only => [:new, :create]
def new
#user = User.new
end
def create
#user = User.new(params[:user])
if #user.save
flash[:notice] = "Registration successful!"
redirect_to root_url
else
render :action => :new
end
end
end
Thanks in advance!

Rails 3 - Nested Resources Routing - One to One relationship

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.

Rspec, CanCan and Devise

I am starting a project and i would like to be able to test everything :)
And i have some problems with CanCan and devise.
For exemple, I have a controller Contacts. Everybody can view and everybody (excepts banned people) can create contact.
#app/controllers/contacts_controller.rb
class ContactsController < ApplicationController
load_and_authorize_resource
def index
#contact = Contact.new
end
def create
#contact = Contact.new(params[:contact])
if #contact.save
respond_to do |f|
f.html { redirect_to root_path, :notice => 'Thanks'}
end
else
respond_to do |f|
f.html { render :action => :index }
end
end
end
end
The code work, but I don't how to test the controller.
I tried this. This works if I comment the load_and_authorize_resource line.
#spec/controllers/contacts_controller_spec.rb
require 'spec_helper'
describe ContactsController do
def mock_contact(stubs={})
(#mock_ak_config ||= mock_model(Contact).as_null_object).tap do |contact|
contact.stub(stubs) unless stubs.empty?
end
end
before (:each) do
# #user = Factory.create(:user)
# sign_in #user
# #ability = Ability.new(#user)
#ability = Object.new
#ability.extend(CanCan::Ability)
#controller.stubs(:current_ability).returns(#ability)
end
describe "GET index" do
it "assigns a new contact as #contact" do
#ability.can :read, Contact
Contact.stub(:new) { mock_contact }
get :index
assigns(:contact).should be(mock_contact)
end
end
describe "POST create" do
describe "with valid params" do
it "assigns a newly created contact as #contact" do
#ability.can :create, Contact
Contact.stub(:new).with({'these' => 'params'}) { mock_contact(:save => true) }
post :create, :contact => {'these' => 'params'}
assigns(:contact).should be(mock_contact)
end
it "redirects to the index of contacts" do
#ability.can :create, Contact
Contact.stub(:new) { mock_contact(:save => true) }
post :create, :contact => {}
response.should redirect_to(root_url)
end
end
describe "with invalid params" do
it "assigns a newly created but unsaved contact as #contact" do
#ability.can :create, Contact
Contact.stub(:new).with({'these' => 'params'}) { mock_contact(:save => false) }
post :create, :contact => {'these' => 'params'}
assigns(:contact).should be(mock_contact)
end
it "re-renders the 'new' template" do
#ability.can :create, Contact
Contact.stub(:new) { mock_contact(:save => false) }
post :create, :contact => {}
response.should render_template("index")
end
end
end
end
But these tests totally failed ....
I saw nothing on the web ... :(
So, if you can advise me on the way i have to follow, i would be glad to ear you :)
CanCan does not call Contact.new(params[:contact]). Instead it calls contact.attributes = params[:contact] later after it has applied some initial attributes based on the current ability permissions.
See Issue #176 for details on this and an alternative solution. I plan to get this fixed in CanCan version 1.5 if not sooner.