Devise + omniauth(facebook) + Profile Model - ruby-on-rails-4

I want to create profile automatically when user is created by devise signup Or by Omniauth-facebook. I have User Model (user.rb)
class User < ActiveRecord::Base
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable,
:omniauthable, :omniauth_providers => [:facebook]
has_many :listings, dependent: :destroy
has_many :bookings, dependent: :destroy
has_one :profile, dependent: :destroy
before_create :build_profile
def self.from_omniauth(auth)
where(provider: auth.provider, uid: auth.uid).first_or_create do |user|
user.email = auth.info.email
user.password = Devise.friendly_token[0,20]
#Profile.where(:user_id => user.id).update_all(name: auth.info.name)
user.build_profile(name: auth.info.name)
end
end
end
But if I use before_create :build_profile and sign_in with Facebook then two profiles are created
and if I use user.build_profile(name: auth.info.name) in self.from_omniauth(auth) then if I sign_up with Devise ..no profile is created.
so where in this code I Build profile ?
My omniauth_callbacks_controller.rb
class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
def facebook
# You need to implement the method below in your model (e.g. app/models/user.rb)
#user = User.from_omniauth(request.env["omniauth.auth"])
if #user.persisted?
sign_in_and_redirect #user, :event => :authentication #this will throw if #user is not activated
set_flash_message(:notice, :success, :kind => "Faceboo") if is_navigational_format?
else
session["devise.facebook_data"] = request.env["omniauth.auth"]
redirect_to new_user_registration_url
end
end
def failure
redirect_to root_path
end
end

Related

How to test a polymorphic association on a controller with Minitest?

I am having trouble making a test pass for my posts controller.
What is the proper way to test my create action inside the Posts controller with a polymorphic association?
I'm using Rails 4
Here's my code
Models:
class Topic < ActiveRecord::Base
belongs_to :user
belongs_to :category
has_many :posts, as: :postable
has_many :posts, dependent: :destroy
validates :name, presence: true, length: {maximum: 50}
validates :description, presence: true, length: {maximum: 80}
validates :user_id, presence: true
is_impressionable
end
class Post < ActiveRecord::Base
belongs_to :user
belongs_to :topic
belongs_to :category
belongs_to :postable, polymorphic: true
has_many :posts, as: :postable
validates :comment, presence: true
validates :user_id, presence: true
validates :topic_id, presence: true
validates :category_id, presence: true
default_scope { order(created_at: :asc) }
end
Post controller
class PostsController < ApplicationController
before_action :auth_user
before_action :set_post, only: [:destroy]
before_action :correct_user, only: [:destroy]
before_action :find_postable, only: [:create, :new]
def new
#post = #postable.posts.build
end
def create
#post = #postable.posts.build(post_params)
set_topic_id
set_category_id
#post.user_id = current_user.id
if #post.save
redirect_to topic_path(#post.topic.id)
else
redirect_to request.referer, notice: "Post unsuccessful!"
end
end
def destroy
#post.destroy
flash[:success] = 'Post deleted'
redirect_to request.referer || root_url
end
private
def set_post
#post = Post.find(params[:id])
end
def correct_user
#post = current_user.posts.find_by(id: params[:id])
redirect_to root_url if #post.nil?
end
def find_topic
#topic = Topic.find(params[:topic_id])
end
def find_postable
#postable = Post.find_by_id(params[:post_id]) if params[:post_id]
#postable = Topic.find_by_id(params[:topic_id]) if
params[:topic_id]
end
def post_params
params.require(:post).permit(:comment)
end
end
Post controller test:
require 'test_helper'
class PostsControllerTest < ActionController::TestCase
def setup
#topic = topics(:topicone)
#post = posts(:postone)
#posttwo = posts(:posttwo)
#category = categories(:categoryone)
#user = users(:user1)
end
test 'should create post when logged in' do
sign_in #user
assert_difference 'Post.count', 1 do
post :create, post: { user_id: #user.id, category_id:
#category.id, topic_id: #topic.id, comment: "First reply!",
postable_id: #post.id, postable_type: "Post" }
end
end
end
When I run the test above I get this error:
ERROR["test_should_create_post_when_logged_in", PostsControllerTest,
2016-12-04 14:23:25 -0500]
test_should_create_post_when_logged_in#PostsControllerTest
(1480879405.93s)
NoMethodError: NoMethodError: undefined method `posts' for nil:NilClass
app/controllers/posts_controller.rb:13:in `create'
test/controllers/posts_controller_test.rb:28:in `block (2
levels) in <class:PostsControllerTest>'
test/controllers/posts_controller_test.rb:25:in `block in
<class:PostsControllerTest>'
app/controllers/posts_controller.rb:13:in `create'
test/controllers/posts_controller_test.rb:28:in `block (2 levels)
in <class:PostsControllerTest>'
test/controllers/posts_controller_test.rb:25:in `block in
<class:PostsControllerTest>'
From my understanding, I believe it's telling me that it can't find whether the create action is posting to a post or to a topic.
The site works great in development and production. The problem is in this test.
How can I rewrite this test and make it so it recognizes to whom it's posting to?
I found a solution for this shortly after.
In this case, to successfully test if a post is created on a topic, make sure to provide the topic_id.
test 'should create post on a topic when logged in' do
sign_in #user
assert_difference 'Post.count', 1 do
post :create, topic_id: #topic, post: {
user_id: #user.id,
category_id: #category.id,
comment: 'First post on a topic!' }
end
end
Now to test if a post is created on another post, make sure to provide the post_id.
test 'should create post on another post when logged in' do
sign_in #user
assert_difference 'Post.count', 1 do
post :create, post_id: #post, post: {
user_id: #user.id,
category_id: #category.id,
comment: 'First post on a topic!' }
end
end

RoR variable doesn't hold associated records

New to RoR, here couldn't find the solution I was looking for so I'm typing my problem here:
I have a web app where after the user is logged in they will be redirected to a dashboard that shows them their various information.
For now - as I'm getting the feel of RoR - the view of the dashboard was suppose to get a lot of information:
def index
#logged_user = Person.includes(:user, :addresses).find(session[:user_id])
end
but when I checked using #logged_user.inspect it only gave me this
#<Person (person model attributes here) >
I checked the log and it seems the User and Addresses were loaded
printscreen of my log http://prntscr.com/c40fee
but they aren't in the #logged_user variable... did I miss a step here? where did I go wrong?
EDIT:
here's the model of Person
class Person < ActiveRecord::Base
validates :first_name, :last_name, presence: true
has_one :user, :dependent => :destroy
has_one :medical_record
has_many :addresses, :dependent => :destroy
has_many :contacts,:dependent => :destroy
has_many :enrollments_as_student, :class_name => 'Enrollment', :foreign_key => :student_id, :dependent => :destroy
accepts_nested_attributes_for :addresses, allow_destroy: true
accepts_nested_attributes_for :contacts, allow_destroy: true
accepts_nested_attributes_for :medical_record, allow_destroy: true
end
model for User
class User < ActiveRecord::Base
validates :username, presence: true
validates :username, :password, format: {with: /\A[a-zA-Z0-9 ñÑ]+\Z/, message: "Special characters aren't allowed"}
validates :username, uniqueness: {message: "username is already taken"}
has_secure_password
belongs_to :person
end
model for Addresses
class Address < ActiveRecord::Base
validates :street, :barangay, :city, :province,
presence: {message: "Fill in all necessary fields"}
validates :zipcode,
numericality: {message: "Zipcodes should only contain numbers"},
length: {minimum: 4, maximum: 4, message: "Invalid zipcode length"}
belongs_to :person
end
also snippet for the login
def login
#user = User.find_by_username(params[:receptions][:username])
if #user && #user.authenticate(params[:receptions][:password])
session[:user_id] = #user.person_id
flash[:notice] = "You have succfully logged in"
redirect_to '/dashboards'
else
flash[:notice] = "Invalid username or password"
redirect_to '/login'
end

Routing Error Using Rails Favorites, Polymorphic

Following a tutorial for adding favorites to my existing project, whereby users can favorite property listings but can't get past the error below:
Routing error,uninitialized constant FavoriteRoomsController
favoriterooms_controller.rb
class FavoriteRoomsController < ApplicationController
before_action :set_room
def create
if Favorite.create(favorited: #room, user: current_user)
redirect_to #room, notice: 'Room has been favorited'
else
redirect_to #room, alert: 'Something went wrong...*sad panda*'
end
end
def destroy
Favorite.where(favorited_id: #room.id, user_id: current_user.id).first.destroy
redirect_to #room, notice: 'Room is no longer in favorites'
end
private
def set_room
#room = Room.find(params[:room_id] || params[:id])
end
end
room.rb
class Room < ActiveRecord::Base
belongs_to :user
has_many :photos
has_many :favorites
geocoded_by :address
after_validation :geocode, if: :address_changed?
validates :home_type, presence: true
validates :room_type, presence: true
validates :accommodate, presence: true
validates :bed_room, presence: true
validates :bath_room, presence: true
validates :listing_name, presence: true, length: {maximum: 50}
validates :summary, presence: true, length: {maximum: 500}
validates :address, presence: true
validates :lister_type, presence: true
validates :gender_type, presence: true
validates :occupation_type, presence: true
validates :move_in, presence: true
validates :term, presence: true
validates :term, presence: true
end
user.rb
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable,
:confirmable, :omniauthable
validates :fullname, presence: true, length: {maximum: 50}
has_many :rooms
has_many :favorites
has_many :favorite_rooms, through: :favorites, source: :favorited, source_type: 'Room'
def self.from_omniauth(auth)
user = User.where(email: auth.info.email).first
if user
return user
else
where(provider: auth.provider, uid: auth.uid).first_or_create do |user|
user.fullname = auth.info.name
user.provider = auth.provider
user.uid = auth.uid
user.email = auth.info.email
user.image = auth.info.image
user.password = Devise.friendly_token[0,20]
end
end
end
end
favorite.rb
class Favorite < ActiveRecord::Base
belongs_to :user
belongs_to :favorited, polymorphic: true
end
routes.rb
Rails.application.routes.draw do
root 'pages#home'
devise_for :users,
:path => '',
:path_names => {:sign_in => 'login', :sign_out => 'logout', :edit => 'profile'},
:controllers => {:omniauth_callbacks => 'omniauth_callbacks',
:registrations => 'registrations'
}
resources :users, only: [:show]
resources :rooms
resources :photos
resources :conversations, only: [:index, :create] do
resources :messages, only: [:index, :create]
end
resources :favorite_rooms, only: [:create, :destroy]
end
roomshow.html.erb
favorites button link code added in my roomsshow.html.erb
<%- unless current_user.favorite_rooms.exists?(id: #room.id) -%>
<%= link_to 'Add to favorites', favorite_rooms_path(room_id: #room), method: :post %>
<%- else -%>
<%= link_to 'Remove from favorites', favorite_room_path(#room), method: :delete %>
<%- end -%>
favorite_rooms_path POST /favorite_rooms(.:format) favorite_rooms#create
favorite_room_path DELETE /favorite_rooms/:id(.:format) favorite_rooms
Screenshot of error message with full trace
I've watched various tututorials and followed numerous suggestions but dont seem to be able to solve the issue by myself.
Routing error,uninitialized constant FavoriteRoomsController
Rails follow naming conventions very strictly and for a good reason. It expects the file names to be in a snake case. So you should change the file name favoriterooms_controller.rb to favorite_rooms_controller.rb

Rails devise after clicking confirmation link user logged in

I want to when a user click the confirmation link after that user should be logged in and redirect to some specific path. I don't have any idea.How can do this?
Now I'm click my account confimation and redirect to sign in page but i want to logged in and redirect to root page
This is my confirmation_instructions.html.erb
<p>Welcome <%= #email %>!</p>
<p>You can confirm your account email through the link below:</p>
<p><%= link_to 'Confirm my account', confirmation_url(#resource, confirmation_token: #token) %></p>
This is User.rb
class User < ActiveRecord::Base
has_paper_trail
acts_as_messageable
rolify
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable, :confirmable,
:recoverable, :rememberable, :trackable, :validatable
has_one :day_care
has_many :actvities, dependent: :destroy
has_one :director, dependent: :destroy
has_one :assistant_director, dependent: :destroy
has_one :teacher, dependent: :destroy
accepts_nested_attributes_for :day_care
accepts_nested_attributes_for :director
accepts_nested_attributes_for :assistant_director
accepts_nested_attributes_for :teacher
def confirm!
super
if confirmed_at_changed? and confirmed_at_was.nil?
UserMailer.welcome_email(self).deliver if self.confirmed_at_changed?
end
end
#def send_welcome_email
# UserMailer.welcome_email(self).deliver if self.confirmed_at_changed?
#end
def mailboxer_email
"#{self.email}"
end
def name
name = ""
if self.has_role? "director"
name = self.director.name
elsif self.has_role? "assistant_director"
name = self.assistant_director.name
elsif self.has_role? "teacher"
name = self.teacher.name
end
name
end
end
Thanks ur help!
In your controller, whichever action you want to make this happen
#user = User.find(params[:id])
sign_in(:user, #user)
redirect_to some_path

Lack of Attributes in Rails + RSpec

I'm attempting to write out some unit tests for my Rails application using RSpec. I'm using Rails 4.0.0 and Rspec-Rails 2.14.6. My User model:
class User < ActiveRecord::Base
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable,
:omniauthable, :omniauth_providers => Settings.authentication.providers.map { |i| i.to_sym }
validates :password, presence: true, allow_nil: true,
allow_blank: true, if: :password_required?
validates :email, presence: true
def password_required?
self.providers.empty?
end
has_many :providers
has_one :profile
end
And my (magical) spec:
require 'spec_helper'
describe User do
describe '.new' do
it 'can create a valid user with no providers' do
params = ActionController::Parameters.new(FactoryGirl.attributes_for :user)
u = User.create params.permit!
expect(u).to be_new_record
end
end
describe '.build_with_provider' do
it 'can create a valid user with a provider' do
puts ap(User)
provider = FactoryGirl.create :provider
oauth_data = FactoryGirl.attributes_for :oauth_data
u = User.build_from_provider_and_oauth_data provider, oauth_data
expect(u).to_not be_nil
expect(u).to be_new_record
expect(u).to be_valid
u.save
expect(u).to be_persisted
end
end
end
If I'm missing something, please let me know. As far as I know, using ActionController::Parameters is the new way of (white|black)listing parameters in Rails 4.