Issue with setting values to a model in rails - ruby-on-rails-3

I have a model named User . I am using Devise for authentication.
The 'User' has many 'Profiles' and one default profile . So I have added a column called 'default' to the User model. I want to store the id of the default profile.
However the code fails at the current_user.default = statement.
Error - undefined method `default=' for #User:0x402c480
class User < ActiveRecord::Base
..........
has_many :profiles
...........
# Setup accessible (or protected) attributes for your model
attr_accessible :email, :password, :password_confirmation, :remember_me, :default
end
.......
class ProfilesController < ApplicationController
before_filter :authenticate_user! ,:except => [:show]
def create
#profile = current_user.profiles.new(params[:profile])
#profile.user = current_user
respond_to do |format|
if #profile.save
#current_user.default= #profile.id
............
end
How do I go about this ? Adding 'default' to the User model doesnt solve the problem.

I suggest you to use STI, it means add "type" column into 'profiles' table
class User < ActiveRecord::Base
has_many :profiles
has_one :profile_default
after_create do
create_profile_default
end
end
class Profile < ActiveRecord::Base
end
class ProfileDefault < Profile
end
def create
#profile = current_user.profiles.new(params[:profile])
#profile.user = current_user
respond_to do |format|
if #profile.save
...
end

Related

Added two "belongs_to" to a Comment model but unable to get one of the associations

I am currently building very simple Comment system on Rails. The primary models are User, Albumpost, and Comment. Users can post Albumposts. For each Albumpost, Users can add Comments to the Albumpost. As a result, a Comment belongs to a User and belongs to an Albumpost.
The problem I'm having is that even with the proper associations in my models (see below), I can't get
#comment.user.name
when I'm trying to render the comments in the albumpost 'show' page (/views/albumposts/show.html.erb). When I go to the page, I can't get #comment.user.name (doesn't understand the association) and get a
"undefined method `name' for nil:NilClass"
Oddly I can get
#comment.albumpost.content
I've double-checked my models and also added the proper foreign keys to the models. Am I doing something wrong in the controllers?
Here are my models:
class Comment < ActiveRecord::Base
attr_accessible :body, :albumpost_id, :user_id
belongs_to :albumpost
belongs_to :user
end
class Albumpost < ActiveRecord::Base
attr_accessible :content
belongs_to :user
has_many :comments, dependent: :destroy
end
class User < ActiveRecord::Base
attr_accessible :name, :email, :password, :password_confirmation
has_many :albumposts, dependent: :destroy
has_many :comments, dependent: :destroy
end
Here are the relevant parts of my Albumpost and Comments controllers:
class AlbumpostsController < ApplicationController
def show
#albumpost = Albumpost.find(params[:id])
#comments = #albumpost.comments
#comment = Comment.new
#comment.albumpost_id = #albumpost.id
#comment.user_id = current_user.id
end
end
class CommentsController < ApplicationController
def create
albumpost_id = params[:comment].delete(:albumpost_id)
#comment = Comment.new(params[:comment])
#comment.albumpost_id = albumpost_id
#comment.user_id = current_user.id
#comment.save
redirect_to albumpost_path(#comment.albumpost)
end
end
I think you should prefer setting objects to relations instead of setting their ids. For example, you should do this:
#comment.user = current_user
instead of
#comment.user_id = current_user.id
ActiveRecord will take care of setting corresponding *_id fields. I'm not sure how it handles the reverse. (it should autoload though, if I understand correctly)

Devise's current_user only works for admins

I've got a standard User model, it has in it an admin boolean. All's well and good for users that have that set to true, but for normal users I get this error:
undefined local variable or method `current_user'
app/models/doc.rb:18:in `mine'
app/controllers/docs_controller.rb:9:in `index'
The Doc model on line 18 reads like this:
def self.mine
where(:user_id => current_user.name, :retired => "active").order('created_at DESC')
end
My User model looks like this:
class User < ActiveRecord::Base
devise :database_authenticatable, :registerable, :recoverable, :rememberable, :trackable, :validatable
attr_accessor :current_password
attr_accessible :name, :password, :password_confirmation, :current_password, :email, :remember_me, :admin
end
class Ability
include CanCan::Ability
def initialize(user)
can :manage, :all if user.admin
end
end
And in my application controller I have the following:
class ApplicationController < ActionController::Base
protect_from_forgery
after_filter :user_activity
rescue_from CanCan::AccessDenied do |exception|
redirect_to root_path
end
def admin?
self.admin == true
end
def authenticate_admin
redirect_to :new_user_session_path unless current_user && current_user.admin?
end
private
def user_activity
current_user.try :touch
end
end
I think that's everything relevant. I can't for the life of me figure this out.
the current_user helper is a controller method that is not accessible from a model. You should pass current user in as a parameter from the controller to the model.
def self.mine(current_user)
where(:user_id => current_user.name, :retired => "active").order('created_at DESC')
end
EDIT: Side note
It looks like user_id is a string in your logic. If this is what you are doing, you should reconsider. Setting up a belongs_to and a has_many with rails using identifiers in the database is far more maintainable. Using string ids is unconventional, and its a rabbit hole that ends in very bad places.

Relationship between models are not working like expected

I have 3 models that are basically nested.
class User < ActiveRecord::Base
attr_accessible :birthday, :name
has_one :advancement, :dependent => :destroy
accepts_nested_attributes_for :advancement
attr_accessible :advancement_attributes
end
class Advancement < ActiveRecord::Base
attr_accessible :user_id, :rank_name
belongs_to :user
has_one :rank, :dependent => :destroy
accepts_nested_attributes_for :_rank
attr_accessible :rank_attributes
end
class Rank < ActiveRecord::Base
attr_accessible :advancement_id, :one_li, :one_pi, :one_date, ...
belongs_to :advancement
end
Here is the controller code I use to create my models.
class UsersController < ApplicationController
def new
#user = User.new
#user.advancement = Advancement.new
#user.advancement.rank = Rank.new
respond_to do |format|
format.html # new.html.erb
end
end
def create
#user = User.new(params[:user])
#user.advancement = Advancement.new
#user.advancement.rank = Rank.new
respond_to do |format|
if #user.save
format.html { redirect_to #user, notice: 'User was successfully created.' }
else
format.html { render action: "new" }
end
end
end
end
In the console I can create relations that work like I would expect. When I try to do this through the browser all of my objects are instantiated, the foreign keys are correct, but if I try to find user.advancement, I get a method missing error. Am I using new or create wrong and if so what should I do? Sorry about the amount of code, but I didnt know any other way to explain it.
To start, in most of your code you reference a "rank" model but the model itself appears to be called "BoyScoutRank". Could this be the issue?
As Thanh pointed out, you have accepts_nested_attributes_for :_rank instead of :rank. You also should not need to create new Advancement and Rank models in your create. The accepts_nested_attributes should handle that for you.
Does the following work (once you fix the :_rank issue):
#user = User.new(params[:user])

CanCan not authorizing nested resource

I have a Ticket model and a TicketReply model:
class Ticket < ActiveRecord::Base
has_many :replies, :class_name => "TicketReply"
end
class TicketReply < ActiveRecord::Base
belongs_to :ticket, :class_name => "Ticket"
end
Here is my list of abilities:
class Ability
include CanCan::Ability
def initialize(user)
can :manage, Ticket, :userid => user.id
can :manage, TicketReply, :ticket => { :userid => user.id }
end
end
And finally my TicketRepliesController:
class TicketRepliesController < AuthorizedController
load_and_authorize_resource :ticket
load_and_authorize_resource :ticket_reply, :through => :ticket
def create
if #ticket_reply.valid?
# ...
else
# ...
end
end
end
However, every time I try to create a ticket reply I get an unauthorized message: "You are not authorized to access this page.".
EDIT: I can access the Ticket itself fine through a TicketsController.
Any idea what I am missing?
In the controller new and create actions, you need to wire your new ticket record with the current_user
class TicketRepliesController < AuthorizedController
... whatever code you have
protected
# override to do the wireing
def build_resource
resource = super
resource.userid = current_user.id # wired!
resource
end
end
Now CanCan will see the link and allow!

How to scope “polymorphic controllers” to current_account in rails3 multi-tenant subdomain styled application

I am trying to use a polymorphic comment model on the post model , upload model, etc. Ordinarily i would have a #parent resource to scope one to the other in order for Rails to build the relationship. But because this a multi-tenant subdomain styled application, where all resources will also need to be scoped to the curent_account. I am struggling with how to scope #parent resource under the current_accout.
In ApplicationController I have a current_account method, a find_parent and a parent_collection method:
#Application_controller
class ApplicationController < ActionController::Base
before_filter :current_account
def current_account
unless is_root_domain?
#current_account ||= Account.find_by_subdomain(request.subdomains.first)
end
#current_account
end
def find_parent
params.each do |name ,value|
#parent = $1.pluralize.classify.constantize.find(value) if name =~ /(.*?)_id/
return if #parent
end
end
def parent_collection
#parent_collection ||= current_account.send parent.pluralize
end
end
#comments_controller with only #parent resource without reference to current_account
class CommentsController < ApplicationController
before_filter :find_parent
def new
#comment = #parent.comments.build
end
def create
#comment = #parent.comments.build(params[:comment])
.....
.....
end
end
#comments_controller using only current_account resource without reference to #parent
class CommentsController < ApplicationController
before_filter :current_account
def new
#comment = current_account.comments.build
end
def create
#comment = current_account.comments.build(params[:comment])
.....
.....
end
end
Any guide on how to call current_accout in the controllers in a way that #parent is scoped to it and is there a need for the parent_collection method that i put in the applications_controller. Thanks
Let's make an assumption that your #parent resource is a Post model. Then I would imagine that:
a) your Account model has_many :posts
b) your Post model belongs_to :account
c) your Post model has_many :comments, :as => :commentable
c) your Comment model belongs_to :commentable, :polymorphic => true
So with that in mind you should be able to build scopes like this:
#parent.where(:account_id => current_account.id).comments
You can also refactor it to the commentable model:
def Post < ActiveRecord::Base
scope :by_account, lambda { |account_id| where(:account_id => account_id) }
end
and the use it in the controller like this:
#parent.by_account(current_account.id).comments