Rails 3, Modeling Question - ruby-on-rails

rails 3 newbie, using Devise for auth...
I want to create the following models:
class Instance < ActiveRecord::Base
has_many :users
has_many :notes
end
class User < ActiveRecord::Base
belongs_to :instance
end
class Note < ActiveRecord::Base
belongs_to :instance
end
To create a new note in the notes_controller.rb
def create
#note = instance.notes.build(params[:note].merge(:instance_id => current_user.instance_id))
end
But I'm getting the following ERROR: "undefined local variable or method `instance' for #"
Ideas?

You haven't assigned anything to "instance" yet, so there's nothing to reference. If you know the instance record already exists in the database, you could do something like:
#instance = current_user.instance
#note = Note.create(:instace_id => #instance.id)
If not, you'd need to check and create it first if necessary, using the same kind of syntax.

Related

Cannot modify association ":has_many." using Ruby on rails

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"

Rails add relative record after save

I have a Rails 3.2 app which contains the following models:
class Costproject < ActiveRecord::Base
has_one :costquestion, :dependent => :destroy
class Costquestion < ActiveRecord::Base
belongs_to :costproject
When I create a costproject, I want one related costquestion created.
In the cosproject model, I tried:
after_save :create_costquestion
protected
def create_costquestion
self.costquestion.build
end
But, self seems to be nil - why is that?
undefined method `build' for nil:NilClass
Thanks for the help!
As other points out the reason, why the error, I wouldn't re-iterate it. And here is a solution you can use :
def create_costquestion
self.build_costquestion
self.save!
end
Check the helper methods comes with this associations from Rails.
Note: your method create_costquestion is what Rails already created for you by its magic. So, better give it a new name which shouldn't overwrite the out of the box method.
Edit: A little change to save the child while saving parent.
class Costproject < ActiveRecord::Base
has_one :costquestion, :dependent => :destroy, autosave: true
costquestion is nil this point. You're pointing to a relationship that doesn't yet exist. If you changed this to be something like this you should be ok:
def create_costquestion
costquestion = Costquestion.build #does this save?
self.costquestion = costquestion
self.save
end

Rails4: undefined method `committed? for Model Object

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?

Rails association works when it doesnt use an instance variable

I'm getting the strangest error I've seen in Rails so far. In my view, I can print out the email associated with a painting if I find the record directly (e.g. Painting.find(15). But if I try to use an instance variable it errors (e.g #painting).
views/paintings/show.html.erb
<%= Painting.find(15).artist.user.email %> # works
<%= #painting.artist.user.email %> # Error: "undefined method 'user' for nil:NilClass"
controllers/paintings_controller.rb
def show
#painting = Painting.find(15)
end
Models: "users", "artists", "paintings".
A user can be an artist. So a user has_one artist.
An artist has_many paintings.
I think you should add associations. This how they should look like:
class User < ActiveRecord::Base
has_one :artist # it's ok
end
class Artist < ActiveRecord::Base
belongs_to :user # add this
has_many :paintings
end
class Painting < ActiveRecord::Base
belongs_to :artist
end
For me both cases works with this associations.
Use
def show
#painting = Painting.find(15).last
end
Currently the second one is returning a 1 element array, but in order to call a dependent method, you must specify 1 item.

accessing associations within before_add callback in Rails 3

In Rails 3.2 I have been looking for a way to traverse the associations of an object within the before_add callback.
So basically my use case is:
class User < ActiveRecord::Base
has_and_belongs_to_many :meetings
end
class Meeting < ActiveRecord::Base
has_and_belongs_to_many :users
has_many :comments, :before_add => :set_owner_id
end
class Comment < ActiveRecord::Base
belongs_to :meeting
end
def set_owner_id(child)
child.owner_id = <<<THE USER ID for #user >>>
end
and I am creating a comment within the context of a user:
#user.meetings.first.comments.create
How do I traverse the associations from within the before_add callback to discover the id of #user? I want to set this at model level. I have been looking at proxy_association, but I may be missing something. Any ideas?
You should probably create the comment in the context of the meeting, no? Either way, you should handle this in the controller since you'll have no access to #user in your model.
#comment = Meeting.find(id).comments.create(owner_id: #user, ... )
But if you insist on your way, do this:
#comment = #user.meetings.first.comments.create(owner_id: #user.id)

Resources