Im trying to make a program in which when a user is created, automatically a corporateprofile is automatically created along with it. However upon trying to view the corporate profile i keep running into the below error..
NameError in CorporateprofilesController#show
uninitialized constant User::Corporateprofiles
I have read through my code over and over for spelling mistakes however no avail, also please note I am using nested routes in which each user has on corporateprofile.
Routes.rb
Myapp::Application.routes.draw do
resources :users do
resources :searches
resources :corporateprofiles
end
end
Corporateprofiles Controller
class CorporateprofilesController < ApplicationController
before_action :require_user
def show
#corporateprofile = current_user.corporateprofiles.find(params[:id])
end
def edit
#corporateprofile = current_user.corporateprofiles.find(params[:id])
end
def update
#corporateprofile = Corporateprofile.find(current_user.corporateprofile.id)
if #corporateprofile.update_attributes(corporateprofile_params)
flash[:success] = "Profile Updated"
redirect_to current_user
else
flash.now[:error] = "Something went wrong"
render edit_user_corporateprofiles_path
end
end
private
def profile_params
params.require(:corporateprofile).permit(:companyname, :companylogo,:companybanner,:companywebsite,:companyindustry,:companytype, :companyheadquarters,:companysize,:companyvideo,:aboutus,:city,:state,:country)
end
end
Corporate Profile Model
class Corporateprofile < ActiveRecord::Base
belongs_to :user
end
User Model
class User < ActiveRecord::Base
after_create :build_profile
has_many :searches, dependent: :destroy
has_one :corporateprofiles, dependent: :destroy
def build_profile
Corporateprofile.create(user: self) # Associations must be defined correctly for this syntax, avoids using ID's directly.
end
has_secure_password
end
Have read all the similar stack overflow posts even the error checking ones however I'm still unable to figure out whats causing the error.
Any help would be so much appreciated
You have an error, because you broke rails naming conventions. So, for table name corporate_profiles:
Model file name should be corporate_profile.rb.
Model class name should be CorporateProfile.
Controller class name should be CorporateProfilesController.
has_one association name should be corporate_profile.
You are getting this error because you set up has_one :corporateprofiles. You used the plural of your model name, but rails expects singular. Therefor it is looking for the class Corporateprofiles.
First off - to fix this, change your Naming
It is convention to name classes CamelCase - so change your model to CorporateProfile. You will have to change your files to corporate_profile(_controller).rb as well.
This also makes your relations much easier to read and write.
class User
has_one :corporate_profile, dependent: :destroy
# ... other stuff
end
Secondly - I would suggest you improve your after_create callback. I find it much nicer to directly access self than calling the other model and defining user: self
def build_profile
self.corporate_profile = CorporateProfile.create
end
Related
I'm working with three tables as follows:
article.rb
class Article < ActiveRecord::Base
has_many :comments
has_many :comentarios, :through => :comments
end
comment.rb
class Comment < ActiveRecord::Base
belongs_to :article
has_many :comentarios
end
and comentario.rb
class Comentario < ActiveRecord::Base
belongs_to :article
end
Everything works fine until I attempt to add a 'comentario' and returns this error
ActiveRecord::HasManyThroughCantAssociateThroughHasOneOrManyReflection in ComentariosController#create
Cannot modify association 'Article#comentarios' because the source reflection class 'Comentario' is associated to 'Comment' via :has_many.
This is the code I use to create a new 'comentario'
comentarios_controller.rb
class ComentariosController < ApplicationController
def new
#comentario = Comentario.new
end
def create
#article = Article.find(params[:article_id])
#comentario = #article.comentarios.create(comentario_params)
redirect_to article_path(#article)
end
private
def comentario_params
params.require(:comentario).permit(:comentador, :comentario)
end
end
The output returns an error in the line where I create #comentario from calling #article but I can't see why since Ruby documentation says that once I associate comentario to article using :through, I can simply call something like #article.comentario.
Any idea of what is causing this error?
or do you have any suggestion on how to achieve this association in any other way?
Ok. The issue is that Rails is confused about which article to use here.
Your Comment model belongs_to :article but also your Commentario belongs_to :article... so if you use #article.commentarios - it's confused as to whether the article refers to the article of the comment or the article of the commentario.
You will probably need to update your form to be more explicit about what you're referring to. A form for the commentario should actually include fields for the comment it creates.
Somebody else had the same problem here. You may wish to look at the solution here: "Cannot modify association because the source reflection class is associated via :has_many"
I am working on a Rails 4 application and recently got into a strange issue. I am looking for your help here. Kindly advise.
A small gist snippet has been created to understand the issue undefined method committed?
Just to summarize everything:
# app/models
class User < ActiveRecord::Base
has_many :responses, dependent: :destroy
end
class Response < ActiveRecord::Base
has_one :report
has_many :points
belongs_to :user
end
class Report < ActiveRecord::Base
belongs_to :response
end
class Point < ActiveRecord::Base
belongs_to :response
end
# config/routes.rb
resources :users do
resources :responses do
resources :action_plans
end
end
# app/controllers/action_plans_controller.rb
class ActionPlansController < ApplicationController
before_filter :response
def new
#report = #response.build_report
5.times do
#response.points.build
end
end
private
def response
#response = current_user.responses.find(params[:id])
end
end
Whenever, I am trying to hit:
http://localhost:3000/users/:user_id/responses/:id/action_plans/new
I get error that says: undefined method `committed?' for Response Object. What I am doing wrong here?
By defining a method called response in your controller you're overriding an internal getter used by Rails. To solve the problem, just use a different name for your before action. The common way of naming the action is to use set_<entity name> so set_response it is.
There is a Response class namespaced inside ActionDispatch (ActionDispatch::Response) and it is used throughout Rails. Can it be the case that you're actually hitting the response object instead of your model? Maybe use pry-rails to debug it from inside?
Let's keep this simple. Let's say I have a User model and a Post model:
class User < ActiveRecord::Base
# id:integer name:string deleted:boolean
has_many :posts
end
class Post < ActiveRecord::Base
# id:integer user_id:integer content:string deleted:boolean
belongs_to :user
end
Now, let's say an admin wants to "delete" (hide) a post. So basically he, through the system, sets a post's deleted attribute to 1. How should I now display this post in the view? Should I create a virtual attribute on the post like this:
class Post < ActiveRecord::Base
# id:integer user_id:integer content:string deleted:boolean
belongs_to :user
def administrated_content
if !self.deleted
self.content
else
"This post has been removed"
end
end
end
While that would work, I want to implement the above in a large number of models, and I can't help feeling that copy+pasting the above comparative into all of my models could be DRYer. A lot dryer.
I also think putting a deleted column in every single deletable model in my app feels a bit cumbersome too. I feel I should have a 'state' table. What are your thoughts on this:
class State
#id:integer #deleted:boolean #deleted_by:integer
belongs_to :user
belongs_to :post
end
and then querying self.state.deleted in the comparator? Would this require a polymorphic table? I've only attempted polymorphic once and I couldn't get it to work. (it was on a pretty complex self-referential model, mind). And this still doesn't address the problem of having a very, very similar class method in my models to check if an instance is deleted or not before displaying content.
In the deleted_by attribute, I'm thinking of placing the admin's id who deleted it. But what about when an admin undelete a post? Maybe I should just have an edited_by id.
How do I set up a dependent: :destroy type relationship between the user and his posts? Because now I want to do this: dependent: :set_deleted_to_0 and I'm not sure how to do this.
Also, we don't simply want to set the post's deleted attributes to 1, because we actually want to change the message our administrated_content gives out. We now want it to say, This post has been removed because of its user has been deleted. I'm sure I could jump in and do something hacky, but I want to do it properly from the start.
I also try to avoid gems when I can because I feel I'm missing out on learning.
I usually use a field named deleted_at for this case:
class Post < ActiveRecord::Base
scope :not_deleted, lambda { where(deleted_at: nil) }
scope :deleted, lambda { where("#{self.table_name}.deleted_at IS NOT NULL") }
def destroy
self.update(deleted_at: DateTime.current)
end
def delete
destroy
end
def deleted?
self.deleted_at.present?
end
# ...
Want to share this functionnality between multiple models?
=> Make an extension of it!
# lib/extensions/act_as_fake_deletable.rb
module ActAsFakeDeletable
# override the model actions
def destroy
self.update(deleted_at: DateTime.current)
end
def delete
self.destroy
end
def undestroy # to "restore" the file
self.update(deleted_at: nil)
end
def undelete
self.undestroy
end
# define new scopes
def self.included(base)
base.class_eval do
scope :destroyed, where("#{self.table_name}.deleted_at IS NOT NULL")
scope :not_destroyed, where(deleted_at: nil)
scope :deleted, lambda { destroyed }
scope :not_deleted, lambda { not_destroyed }
end
end
end
class ActiveRecord::Base
def self.act_as_fake_deletable(options = {})
alias_method :destroy!, :destroy
alias_method :delete!, :delete
include ActAsFakeDeletable
options = { field_to_hide: :content, message_to_show_instead: "This content has been deleted" }.merge!(options)
define_method options[:field_to_hide].to_sym do
return options[:message_to_show_instead] if self.deleted_at.present?
self.read_attribute options[:field_to_hide].to_sym
end
end
end
Usage:
class Post < ActiveRecord::Base
act_as_fake_deletable
Overwriting the defaults:
class Book < ActiveRecord::Base
act_as_fake_deletable field_to_hide: :title, message_to_show_instead: "This book has been deleted man, sorry!"
Boom! Done.
Warning: This module overwrite the ActiveRecord's destroy and delete methods, which means you won't be able to destroy your record using those methods anymore. Instead of overwriting you could create a new method, named soft_destroy for example. So in your app (or console), you would use soft_destroy when relevant and use the destroy/delete methods when you really want to "hard destroy" the record.
I have a set of nested resources consisting of users, books, and chapters. Here's how it looks.
Models
class User
has_many :books, dependent: :destroy
accepts_nested_attributes_for :books, allow_destroy: true
end
class Book
belongs_to :user
has_many :chapters, dependent: :destroy
accepts_nested_attributes_for :chapters, allow_destroy: true
end
class Chapter
belongs_to :book
end
Chapter Controller
def create
#chapter = #book.chapters.build(params[:chapter])
if #chapter.save
flash[:success] = "A new chapter created!"
redirect_to blah blah
else
render 'new'
end
end
protected
def get_book
#book = Book.find(params[:chapter][:book_id]) ||
Book.find(params[:book_id])
end
You might be wondering why I have that protected method. I'm trying to let users create chapters and books in separate pages and still have the convenience of having nested resources. So a user can create a chapter on the chapter creation page and associate the chapter with the right book via association form.
Currently I'm stuck because the chapter resource is not getting the user id it needs. I'm very new to web development so I might be doing some crazy things here. Any help would be greatly appreciated. I really want to get this to work.
EDIT: To give more detail on what I meant by "the chapter resource is not getting the user id it needs" - in the chapter model I wrote *validates :user_id, presence: true*. When I press the submit button on the chapter creation page, it gives an error saying user_id cannot be blank.
In order to be sure that the current user owns the chapter, and therefore the book, change the get_book method to
def get_book
#book = current_user.books.find(params.fetch(:chapter, {})[:book_id] || params[:book_id])
end
params.fetch makes sure that you don't get an exception when params[:chapter] is nil
I don't think the Chapter model should check that the user_id is present. Instead, the controller should have a before_filter that checks if the action is authorized for the current user.
Something like this:
class ChaptersController < ApplicationController
before_filter :authorized?, only: [:create]
def create
...
end
private
def authorized?
current_user && current_user.owns? Chapter.find(params[:id])
end
end
owns? would then be implemented on the User model, and current_user would be implemented in the ApplicationController.
So, I've read in some book about tip "Use model association", which encourages developers to use build methods instead of putting ids via setters.
Assume you have multiple has_many relationships in your model. What's best practise for creating model then ?
For example, let's say you have models Article, User and Group.
class Article < ActiveRecord::Base
belongs_to :user
belongs_to :subdomain
end
class User < ActiveRecord::Base
has_many :articles
end
class Subdomain < ActiveRecord::Base
has_many :articles
end
and ArticlesController:
class ArticlesController < ApplicationController
def create
# let's say we have methods current_user which returns current user and current_subdomain which gets current subdomain
# so, what I need here is a way to set subdomain_id to current_subdomain.id and user_id to current_user.id
#article = current_user.articles.build(params[:article])
#article.subdomain_id = current_subdomain.id
# or Dogbert's suggestion
#article.subdomain = current_subdomain
#article.save
end
end
Is there a cleaner way ?
Thanks!
This should be a little cleaner.
#article.subdomain = current_subdomain
The only thing I can think of is merging the subdomain with params:
#article = current_user.articles.build(params[:article].merge(:subdomain => current_subdomain))