Rails 3 Checking a relationship count - ruby-on-rails

I have a User & Profile Models. A user has_one profile IE.
class User < ActiveRecord::Base
has_secure_password
# Relationships
has_one :profile
class Profile < ActiveRecord::Base
# Relationships
belongs_to :user
I am then trying to test to see if the user has a profile. If not redirect them to the profile controller ie.
class User::BaseController < ApplicationController
# Filters
before_filter :check_for_profile
# Layout
layout "backend"
# Helpers
helper_method :current_user
private
def current_user
#current_user ||= User.find(session[:user_id]) if session[:user_id]
end
def check_for_profile
if current_user.profile.empty?
redirect_to new_user_profile_path, :notice => "Please create a profile first."
end
end
end
No matter what I try I'm getting the error.
You have a nil object when you didn't expect it!
You might have expected an instance of Array.
The error occurred while evaluating nil.empty?
I'm pretty sure my relationships are right. Can anyone shed some light on what I'm doing wrong ?
Thank you in advance.
Lee

try profile.blank? instead. empty? is not defined for nil.

Check out the "blank?" method at the following link. The "present?" method should also be considered - they're basically the same.
http://api.rubyonrails.org/classes/Object.html#method-i-blank-3F

Related

What's the best way to make a new model when overriding the Devise User Controller?

I'm trying to make it so that when a new User is created (through Devise), a new Household(essentially a group) model will be created if no previous Household model with that name exists.
pseudocode:
if Household.find(params[:household_name))
# allow current_user to join household
else
# create new Household model with User's household_name parameter
end
I've overwritten the base user controller from Devise::RegistrationsController with controllers/registerhousehold_controller.rb:
class RegisterhouseholdController < Devise::RegistrationsController
But I'm not sure how to implement the actual creation here. Any suggestions?
No changes in controller required as far as I see.
User.rb
after_create :create_or_join_to_household
def create_or_join_to_household
household = Household.find(params[:household_name])
if household.present?
self.join_to_household
else
Household.create(name: params[:household_name])
#or self.households.create(name: params[:household_name])
#if you have a household - user relation somehow
end
p.s.
join_to_household would be another method in your user model that will create a household_users relation.
Simple - use the before_create callback in the user model to build the object, then you'll be able to use it when you save:
#app/models/user.rb
Class User < ActiveRecord::Base
before_create :set_household, if: Proc.new {|user| user.household_id.present? }
private
def set_household
if house = Household.find(self.household_id)
#if it is set
else
#create a new houshold
end
end
end
I had to call custom method after successful sign up, on my previous task.
U also need something similar.
I'm not sure about overriding.
Try this in App. controller
class ApplicationController < ActionController::Base
def after_sign_in_path_for(resource)
if Household.find(params[:household_name))
# allow current_user to join household
else
#create new Household model with User's household_name parameter
end
root_path
end
end
Check this

Rails - obfuscate_id errors on find() in ApplicationController

I am using the obfuscate_id gem ( https://github.com/namick/obfuscate_id ).
We obfuscate ID's by inserting one line into the top of each model:
obfuscate_id
It works great and as expected. My ID's are obfuscated.
However, as part of some logic in my ApplicationController, I have some logic to check the current user and each controller has access to these methods as helpers:
def current_user
#current_user ||= User.find(session[:user_id]) if session[:user_id]
end
However, I get an error:
Couldn't find User with id=5164061535
It doesn't seem to be able to convert the obfuscated ID back to its normal form for a find().
How can I get the controllers to recognise this obfuscation that's made in each model.
My user model is like so:
class User < ActiveRecord::Base
# This part obfuscates the user ID
obfuscate_id
has_one :profile, dependent: :destroy
has_many :pins
has_many :replies, through: :pins
end
Any ideas how I can get the ApplicationController to recognise this? Doing find() in each controller itself is fine, but as ApplicationController doesn't have its own model, it doesn't seem to know of it.
Thanks,
Michael.
Try this...
#current_user ||= User.find(User.deobfuscate_id(session[:user_id])) if session[:user_id]
Weirdly enough, I ended up trying this:
#current_user ||= User.find_by_id(session[:user_id]) if session[:user_id]
And it worked! But, why?
User.find() in itself was not working with this gem. So, although it's now working, it concerns me a little as to why exactly.
If anyone could add anything here that'd be great.
Thanks!

How can I make a condition with current_user in controller

I'm a freshman to learn Rails and working on my first project about online book writing.
I've already made the MVC of user,book and section. I wanna create a button called "Author Place",which can show all the pieces written by the current logged in user.
I wanna ask a simple question. How can I make a condition with the current username to select the current author's works from the book database. Should I put this code in controller or view?
Code as follow.
current_user method of the ApplicationController:
protect_from_forgery
helper_method :current_user
private
def current_user
#current_user ||= User.find(session[:user_id]) if session[:user_id]
end
The Section model :
class Section < ActiveRecord::Base
attr_accessible :book_id, :section_content, :section_tag, :user_username
belongs_to :book
belongs_to :user
end
The Section controller :
class SectionsController < ApplicationController
def userpieces
#sections=Section.find(:all, :conditions=>"user_username=current_user.username") # This part doesn't work
end
end
Or any suggestions with some other way to do this?
Assuming you have a corresponding has_many :sections association in your User model, try this:
#sections = current_user.sections
As depa and izuriel mentioned, you should be able to get it simply if your model relation is correctly set.
Anyway, if you wish to get it in the way you try please use:
#sections=Section.find(:all, :conditions => ["user_username= ?",current_user.username])
Please note, in rails 3, .find(:all is deprecated, please use .all instead.

Why it happen error that could not find user happen when I destroy user from grouping table

all I'm new be to rails.
I want to destroy user that have group_id in grouping table.
My source code is here.
GroupsController
def leave
#user = current_user
#group = Group.find(params[:id])
#user.groupings.find_by_group_id(#group).destroy
redirect_to :back , notice: "Destroy!"
end
lists.html.haml
%td= link_to("Destroy",leave_group_path(:id => group),:confirm => "Are you sure",:method => :delete)
When I click "Destroy" button , then it happen error that Couldn't find User with id=1
I want to destroy only grouping table, but why can't find current_user.I don't remove current_user.
Error logs is that
app/controllers/application_controller.rb:6:in `current_user'
And current_user is provided helper_method of OmniAuth Plugin.
current_user is implemented following this ..
class ApplicationController < ActionController::Base
protect_from_forgery
private
def current_user
#current_user ||= User.find(session[:user_id]) if session[:user_id]
end
helper_method :current_user
end
Please some help.
Thanks in advance.
If there is an error that says could not find user with id=1 then there is not user with id=1.
Ofte we delete/destroy the user.
In rails when you destroy the record with id = 1 and create another record then the newly created records id will not be 1. This could have happened the case with you.
Also, your association in models is this, i am guessing ::
User Model
class User < ActiveRecord::Base
has_many :groups # not groupings
end
Group model #as mentioned in the question.
class Group < ActiveRecord::Base
belongs_to :user
end
This means ::
#user.groupings.find_by_group_id(#group).destroy could not possible be correct.
Instead try this ::
#user.groups.find_by_group_id(#group).destroy
Since, a user has_many groups and not groupings.
Read More about naming conventions

How to test a named_scope that references a class attribute with Shoulda?

I have the following ActiveRecord classes:
class User < ActiveRecord::Base
cattr_accessor :current_user
has_many :batch_records
end
class BatchRecord < ActiveRecord::Base
belongs_to :user
named_scope :current_user, lambda {
{ :conditions => { :user_id => User.current_user && User.current_user.id } }
}
end
and I'm trying to test the named_scope :current_user using Shoulda but the following does not work.
class BatchRecordTest < ActiveSupport::TestCase
setup do
User.current_user = Factory(:user)
end
should_have_named_scope :current_user,
:conditions => { :assigned_to_id => User.current_user }
end
The reason it doesn't work is because the call to User.current_user in the should_have_named_scope method is being evaluated when the class is being defined and I'm change the value of current_user afterwards in the setup block when running the test.
Here is what I did come up with to test this named_scope:
class BatchRecordTest < ActiveSupport::TestCase
context "with User.current_user set" do
setup do
mock_user = flexmock('user', :id => 1)
flexmock(User).should_receive(:current_user).and_return(mock_user)
end
should_have_named_scope :current_user,
:conditions => { :assigned_to_id => 1 }
end
end
So how would you test this using Shoulda?
I think you are going about this the wrong way. Firstly, why do you need to use a named scope? Wont this just do?
class BatchRecord < ActiveRecord::Base
belongs_to :user
def current_user
self.user.class.current_user
end
end
In which case it would be trivial to test. BUT! WTF are you defining current_user as a class attribute? Now that Rails 2.2 is "threadsafe" what would happen if you were running your app in two seperate threads? One user would login, setting the current_user for ALL User instances. Now another user with admin privileges logs in and current_user is switched to their instance. When the first user goes to the next page he/she will have access to the other persons account with their admin privileges! Shock! Horror!
What I reccomend doing in this case is to either making a new controller method current_user which returns the current user's User instance. You can also go one step further and create a wrapper model like:
class CurrentUser
attr_reader :user, :session
def initialize(user, session)
#user, #session = user, session
end
def authenticated?
...
end
def method_missing(*args)
user.send(*args) if authenticated?
end
end
Oh, and by the way, now I look at your question again perhaps one of the reasons it isn't working is that the line User.current_user && User.current_user.id will return a boolean, rather than the Integer you want it to. EDIT I'm an idiot.
Named scope is really the absolutely wrong way of doing this. Named scope is meant to return collections, rather than individual records (which is another reason this fails). It is also making an unnecessary call the the DB resulting in a query that you don't need.
I just realized the answer is staring right at me. I should be working from the other side of the association which would be current_user.batch_records. Then I simply test the named_scope on the User model and everything is fine.
#Chris Lloyd - Regarding the thread safety issue, the current_user attribute is being set by a before_filter in my ApplicationController, so it is modified per request. I understand that there is still the potential for disaster if I chose to run in a multi-threaded environment (which is currently not the case). That solution I suppose would be another topic entirely.

Resources