rails devise user external api - ruby-on-rails

I am trying to setup a newsletter signup procedure when a new user signs up. I am using Mailchimp via gibbon to handle the newsletters. I have added a subscribe attribute to my model and a getter and setter method. I also have added the subscribe checkbox to my form. What I need to do is if the form box is checked subscribe the user to the email on creation.
model
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :token_authenticatable, :confirmable,
# :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
# Setup accessible (or protected) attributes for your model
attr_accessible :email, :password, :password_confirmation, :remember_me, :username, :subscribe
validates :username, presence: true
validates_uniqueness_of :username
has_many :contest_entries, dependent: :destroy
has_many :votes, dependent: :destroy
def subscribe=(join)
puts "called subscribe with #{join}"
if join
Gibbon.new.list_subscribe(:id => "blah", :email_address => self.email)
end
end
def subscribe
subscribe ||= false
end
end
Form view
<h2>Sign up</h2>
<%= form_for(resource, :as => resource_name, :url => registration_path(resource_name)) do |f| %>
<%= devise_error_messages! %>
<p><%= f.label :username %><br />
<%= f.text_field :username %></p>
<div><%= f.label :email %><br />
<%= f.email_field :email %></div>
<div><%= f.label :password %><br />
<%= f.password_field :password %></div>
<div><%= f.label :password_confirmation %><br />
<%= f.password_field :password_confirmation %></div>
<div><%= f.label :subscribe, "Subscribe to Newsletter?" %><br />
<%= f.check_box :subscribe, :checked => true %></div>
<div><%= f.submit "Sign up" %></div>
<% end %>
<%= render "devise/shared/links" %>
I was hoping that by adding the attr_accessible and a method it would call the api from the contoller automatically, but it does not seem to be called.
Any advice on how to handle this? I could also use advice on how to test with RSPEC to make sure it is being called.
Thanks,
Cory

Ok I figured out the issue. The problem was with the check for join inside the setter method. Since it was a checkbox, I needed to check for a matching integer of 1.
def subscribe=(join)
begin
if join.to_i == 1
gb = Gibbon.new
result = gb.list_subscribe(:id => "blah", :email_address => self.email)
end
rescue
false
end
end

Related

Additional parameters added in Devise not allowing user registration

I'm currently running the following:
Rails 4.0.2
Devise 3.2.2
I've added three attributes to my user sign up form and also permitted the parameters in Devise in my application controller per the Devise documentation.
My problem now is that when I attempt to sign up I get the following error:
2 errors prohibited this user from being saved
Email can't be blank
Password can't be blank
I've permitted the additional parameters in my application controller as you can see below:
class ApplicationController < ActionController::Base
# 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?
protected
def configure_permitted_parameters
devise_parameter_sanitizer.for(:sign_up) { |u| u.permit(:first_name, :last_name, :profile_name, :email, :password, :password_confirmation) }
end
end
My user model:
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
end
And lastly my sign up form:
<h2>Sign up</h2>
<%= form_for(resource, :as => resource_name, :url => registration_path(resource_name)) do |f| %>
<%= devise_error_messages! %>
<div><%= f.label :first_name %><br />
<%= f.text_field :first_name, :autofocus => true %></div>
<div><%= f.label :last_name %><br />
<%= f.text_field :last_name %></div>
<div><%= f.label :profile_name %><br />
<%= f.text_field :profile_name %></div>
<div><%= f.label :email %><br />
<%= f.email_field :email %></div>
<div><%= f.label :password %><br />
<%= f.password_field :password %></div>
<div><%= f.label :password_confirmation %><br />
<%= f.password_field :password_confirmation %></div>
<div><%= f.submit "Sign up" %></div>
<% end %>
<%= render "devise/shared/links" %>
I've tried two different variations to allow the additional parameters but I am still getting the same error message. Any ideas that I can try?
Thank you
Run gem uninstall protected_attributes, then bundle install, then restart the rails server.
(I'm just posting sapmub's above comment as an answer. Thank you for your help sapmub!)

Create nested forms using Devise

I'm trying to build a nested form using Devise, keeping the devise featuring as sending an email when a new user signs up. I would like to have something like this:
<%= form_for(resource, :as => resource_name, :url => registration_path(resource_name)) do |f| %>
<%= devise_error_messages! %>
<%= f.fields_for(:information) do |info| %>
<div><%= info.text_field :name, :placeholder => 'Nome' %></div>
<div><%= info.text_field :surname, :placeholder => 'Cognome' %></div>
<% end %>
<div><%= f.email_field :email, :autofocus => true, :placeholder => 'E-mail' %></div>
<div><%= f.password_field :password, :placeholder => 'Password' %></div>
<div><%= f.password_field :password_confirmation, :placeholder => 'Conferma password' %></div>
<div><%= f.submit "Registrati", class: "btn btn-large btn-info" %></div>
<% end %>
In my route.rb
devise_for :users, :controllers => { :registrations => "users" }
In my user.rb
class User < ActiveRecord::Base
has_one :information, dependent: :destroy
# Include default devise modules. Others available are:
# :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable,
:validatable, :confirmable, :lockable
accepts_nested_attributes_for :information, update_only: true
end
and in information.rb
class Information < ActiveRecord::Base
belongs_to :user
end
in users_controller.rb
class UsersController < Devise::RegistrationsController
def new
super
resource.build_information
end
end
But nothing happen, or better the 2 fields name and surname don't appear, but I don't receive an error message
Here is what I would do,
I would move this line from the controller to the view(fields_for takes 2 parameters). Like below,
Controller
def new
super
resource.build_information #remove from here
end
View
<!--Added here -->
<%= f.fields_for(:information,resource.build_information) do |info| %>
Must work now!
OR
Just change
<%= form_for(resource, :as => res.....
to
<%= form_for(#resource, :as => res
Note "#", this will work. Remove build_information both from view and controller.

Creating Profile for Devise users

So I took the steps described in Profile model for Devise users?
I'm using rails 4 and ruby 1.9.3p448
class User < ActiveRecord::Base
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
attr_accessible :email, :password, :password_confirmation, :remember_me, :profile_attributes
has_one :profile
accepts_nested_attributes_for :profile
protected
def profile
super || build_profile
end
end
#
class Profile < ActiveRecord::Base
belongs_to :user
attr_accessible :uname, :manager
end
#
<h2>Sign up...</h2>
<%= form_for resource, :as => resource_name, :url => registration_path(resource_name) do |f| %>
<%= devise_error_messages! %>
<div><%= f.label :email %><br />
<%= f.email_field :email, :autofocus => true %></div>
<div><%= f.label :password %><br />
<%= f.password_field :password %></div>
<div><%= f.label :password_confirmation %><br />
<%= f.password_field :password_confirmation %></div>
<%= f.fields_for :profile do |profile_form| %>
<h2><%= profile_form.label :uname %></h2>
<p><%= profile_form.text_field :uname %></p>
<h2><%= profile_form.label :manager %></h2>
<p><%= profile_form.text_field :manager %></p>
<% end %>
<div><%= f.submit "Sign up" %></div>
<% end %>
<%= render "devise/shared/links" %>
#
Still can't save profile for user and this is the output:
Parameters: {"utf8"=>"✓", "authenticity_token"=>"kG7S9lF4+5hm+ggmKA4LZyXrN4hsPf01jGQvKxgzGGI=", "user"=>{"email"=>"test1#test.test", "password"=>"[FILTERED]", "password_confirmation"=>"[FILTERED]", "profile_attributes"=>{"uname"=>"1", "manager"=>"1"}}, "commit"=>"Sign up"} **Unpermitted parameters: profile_attributes**
Shoud I do anything in Profiles controller?
Thanks in advance
I found the solution!
In my users/registrations_controller.rb, I had to add the following
before_filter :configure_permitted_parameters, if: :devise_controller?
def configure_permitted_parameters
devise_parameter_sanitizer.for(:sign_up) {|u|
u.permit(:email, :password, :password_confirmation, :remember_me,
profile_attributes: [:uname, :manager])}
end
and it works just fine!
Rails 4 has stopped using attr_accessible and has started using strong parameters -http://api.rubyonrails.org/classes/ActionController/StrongParameters.html
You'll need to add your nested attributes for profile into the permitted attributes in the user controller.

How to avoid "Can't mass-assign protected attributes" error

Even though I added accepts_nested_attributes_for to my model.
it still says "Can't mass-assign protected attributes"
What else am I supposed to do in order to avoid this???
models/user.rb
class User < ActiveRecord::Base
validates_presence_of :username
validates_uniqueness_of :username
validates_length_of :username, :within => 4..10
acts_as_messageable
has_one :user_profile
accepts_nested_attributes_for :user_profile
# Include default devise modules. Others available are:
# :token_authenticatable, :encryptable, :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable, :confirmable,
:recoverable, :rememberable, :trackable, :validatable
# Setup accessible (or protected) attributes for your model
attr_accessible :email, :password, :password_confirmation, :remember_me, :username, :user_profile_attributes
def mailboxer_email(message)
email
end
# def name
# email
# end
end
models/user_profile.rb
class UserProfile < ActiveRecord::Base
belongs_to :user
accepts_nested_attributes_for :user
attr_accessible :nickname
end
views/registration/edit.html.erb
<h2>Edit <%= resource_name.to_s.humanize %></h2>
<%= form_for(resource, :as => resource_name, :url => registration_path(resource_name), :html => { :method => :put }) do |f| %>
<%= devise_error_messages! %>
<div class="field">
<%= f.label :nickname %><br />
<%= f.fields_for :nickname_attributes, #user.user_profile do |user_profile| %>
<%= user_profile.text_field :nickname %>
<% end %>
</div>
<div><%= f.label :email %><br />
<%= f.email_field :email %></div>
<div><%= f.label :password %> <i>(leave blank if you don't want to change it)</i><br />
<%= f.password_field :password %></div>
<div><%= f.label :password_confirmation %><br />
<%= f.password_field :password_confirmation %></div>
<div><%= f.label :current_password %> <i>(we need your current password to confirm your changes)</i><br />
<%= f.password_field :current_password %></div>
<%= recaptcha_tags :display => {:theme => 'red'} %>
<div><%= f.submit "Update" %></div>
<% end %>
<h3>Cancel my account</h3>
<p>Unhappy? <%= link_to "Cancel my account", registration_path(resource_name), :confirm => "Are you sure?", :method => :delete %>.</p>
<%= link_to "Back", :back %>
attr_accessible defines the attributes you want the user to be able to mass assign. Just make sure it has all the attributes you want in there.
To be fair, you can remove attr_accessible if you don't care about it and the error will disappear (but all your model fields will be mass assignable).
in edit.html.erb
wrong:
f.fields_for :nickname_attributes,
correct:
f.fields_for :user_profile_attributes,

rails devise: user and account model

Hi I am trying to customize the sign up page by adding an additional field, name.
This is done by adding a Profile model to my app.
class Profile < ActiveRecord::Base
belongs_to :user
end
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :token_authenticatable, :encryptable, :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
# Setup accessible (or protected) attributes for your model
attr_accessible :email, :password, :password_confirmation, :remember_me, :profile_attributes
has_one :profile, :dependent => :destroy
accepts_nested_attributes_for :profile
end
I overrode the registration model:
# app/controllers/registrations_controller.rb
class RegistrationsController < Devise::RegistrationsController
def new
super
profile = #user.build_profile
end
def create
super
end
def update
super
end
end
And my new sign up page:
<h2>Sign up</h2>
<%= form_for(resource, :as => resource_name, :url => registration_path(resource_name)) do |f| %>
<%= devise_error_messages! %>
<div><%= f.label :email %><br />
<%= f.email_field :email %></div>
<div><%= f.label :password %><br />
<%= f.password_field :password %></div>
<div><%= f.label :password_confirmation %><br />
<%= f.password_field :password_confirmation %></div>
<div><% f.fields_for :profile do |builder| %>
<p><%= builder.label :name %></p>
<p><%= builder.text_field :name %></p>
<% end %></div>
<div><%= f.submit "Sign up" %></div>
<% end %>
<%= render "links" %>
However, I am not sure if everything else works, but the registration page still looks the same. That is, it doesn't show the name input field. How do I fix this?
What am I missing?
I suspect you did not generate the views. Did you run the following?
rails generate devise:views
More information on changing views can be found in "Configuring views" on the devise wiki:
https://github.com/plataformatec/devise
Thanks,
Tabrez

Resources