undefined method `model_name' for NilClass:Class - Rails application - ruby-on-rails

So I have seen other articles here on stack about this and a lot of the time people are not doing #post = post.new. I read some where to use the plural...??
any ways I am getting this error on my discussion code:
Model
class Discussion < ActiveRecord::Base
has_many :comment
belongs_to :author
attr_accessible :author_id, :content, :title
validate :comment, :presence => true
validate :title, :presence => true
end
Discussion Controller
class DiscussionsController < ApplicationController
def index
#discussion = Discussion.new
#discussions = Discussion.all
end
def create
#discussion = Discussion.create(params[:discussion])
if #discussion.save
redirect_to tasks_path, :flash => {:success => 'Created a new discussion'}
else
redirect_to tasks_path, :flash => {:error => 'Failed to create a discussion'}
end
end
end
Discussion Form
<%= form_for #discussion do |f| %>
<p><%= f.label :title %>
<%= f.text_field :title %></p>
<p><%= f.label :content %>
<%= f.text_area :content %></p>
<% end %>
Discussion Routes
resources :discussions do
resources :comments
end
Now as far as I know I am doing this right, because I have a task form set up essentially the same way - but I have looked at my code for hours and have googled and tried other examples and now i see this:
undefined method `model_name' for NilClass:Class
Extracted source (around line #1):
1: <%= form_for #discussion do |f| %>
2:
3: <p><%= f.label :title %>
4: <%= f.text_field :title %></p>
Which should mean that I am missing something from my controller.....is it as asilly as a spelling mistake? >.>

Have you tried putting this in your discussion controller?
def new
#discussion = Discussion.new
end

I believe your problem is that you are trying to create a discussion on a task form but have only defined the discussion controller and not the task controller.

u have to add :method => :post to the form for creating the object else the form will get submitted with GET request.
<%= form_for #discussion , :method => :post do |f| %>

Is that the index view that has the form_for?
If not, then you should add a new action to the controller and do #discussion = Discussion.new there and not in your index action.

if ur model relationships are exactly as u have provided, then they are incorrect
class Discussion < ActiveRecord::Base
has_many :comment #has_many :comments
belongs_to :author
attr_accessible :author_id, :content, :title
validate :comment, :presence => true #valide :comments, :presence => true
validate :title, :presence => true
end

Related

undefined method `model_name' for NewThread::ActiveRecord_Relation:Class

I read hundreds of questions with same issue but couldn't figure it out. here is my form:
<%= form_for(#new_thread, :url => {:action => 'create'}) do |f| %>
<div class="field">
<%= f.label :title %><br>
<%= f.text_field :title %>
</div>
<div class="field">
<%= f.label :description %><br>
<%= f.text_field :description %>
</div>
<div>
<%= f.hidden_field :user_id, :value => current_user.id %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
my controller:
def new
#new_thread = NewThread.new
end
def create
#new_thread = NewThread.new(new_thread_params)
# Save the object
if #new_thread.save
# If save succeeds, redirect to the list action
flash[:notice] = "Thread created."
redirect_to(:action => 'index')
else
# If save fails, redisplay the form so user can fix problems
#new_thread = NewThread.order('id ASC')
render('new')
end
end
private
# Use callbacks to share common setup or constraints between actions.
# Never trust parameters from the scary internet, only allow the white list through.
def new_thread_params
params.require(:new_thread).permit(:title, :description, :user_id)
end
my model:
class NewThread < ActiveRecord::Base
has_many :replies, :dependent => :destroy
belongs_to :user
has_many :like_counts, :dependent => :destroy
has_many :dislike_counts, :dependent => :destroy
has_many :new_thread_flags, :dependent => :destroy
validates_presence_of :title
validates_presence_of :description
end
my routes associated with new_thread:
GET /new_threads(.:format) new_threads#index
POST /new_threads(.:format) new_threads#create
new_new_thread GET /new_threads/new(.:format) new_threads#new
edit_new_thread GET /new_threads/:id/edit(.:format) new_threads#edit
new_thread GET /new_threads/:id(.:format) new_threads#show
PATCH /new_threads/:id(.:format) new_threads#update
PUT /new_threads/:id(.:format) new_threads#update
DELETE /new_threads/:id(.:format) new_threads#destroy
DELETE /reply_flags/:id(.:format) reply_flags#destroy
new_threads_search POST /new_threads/search(.:format) new_threads#search
root GET / new_threads#list
everything looks just fine. when i submit my form with empty fields i get this :
undefined method `model_name' for NewThread::ActiveRecord_Relation:Class
otherwise it works just fine. i use the same form partial for update and there validations work too. i am using rails 4.
The problem is here, where you initialize a new #new_thread after the save fails:
#new_thread = NewThread.order('id ASC')
What are you expecting to happen there? Perhaps you meant this?
#new_thread = NewThread.order('id ASC').first
Without choosing one of the NewThreads, the view will try to render the whole collection of them.
You should remove this line:
#new_thread = NewThread.order('id ASC')
Otherwise when save fails you will give user different model to edit. You have already assigned #new_thread so all will work.

Ruby on rails NoMethodError in custom controller action

Maybe someone could tell me how to create or correctly pass params from partial form_for to custom controller? Here is what i got so far:
Basically there are two classes: Scribbles (polymorphic - connected to local feeds) and local feeds. Trough command line, I can create scribbles, assign them to local feeds and display them in html. But creating them in trough different controller seems to be a rather tricky task. Any help would be appreciated.
Scribble.rb
class Scribble < ActiveRecord::Base
attr_accessible :post, :comments_attributes, :user_id, :posted_by, :localfeed_attributes
belongs_to :scribbled, :polymorphic => true
has_many :comments, :as => :commentable
accepts_nested_attributes_for :comments
end
localfeed.rb
class Localfeed < ActiveRecord::Base
attr_accessible :city, :scribble_id, :location_id, :localfeed_id, :scribble_attributes
belongs_to :location
has_many :scribbles, :as => :scribbled
accepts_nested_attributes_for :scribbles
validates :city, :presence => true, :uniqueness => true
Here is the error
NoMethodError in LocalfeedsController#newlocalscribble
undefined method `scribbles' for nil:NilClass
Rails.root: c:/workspace/uu2
Application Trace | Framework Trace | Full Trace
app/controllers/localfeeds_controller.rb:80:in `newlocalscribble'
localfeeds/show.erb.html
<% #newlocalscribble = #localfeed.scribbles.new %>
<%=render :partial => 'newlocalscribble.html.erb', :locals => {:newlocalscribble => #newlocalscribble, :localfeed => #localfeed}%>
localfeeds/_newlocalscribble.html.erb
<%= form_for #newlocalscribble, :remote => true, :url => url_for(:controller => 'localfeeds', :action => 'newlocalscribble') do |f| %>
<div class="">
<div class="field">
<%= f.text_area :post,:rows=>3,:placeholder=>"What's on your mind,#{current_user.full_name}?", :class=>"sribble-status-text" %>
<%= f.hidden_field :localfeed, :value => #localfeed.id%>
</div>
<div class="sribble-status-actions" id="newlocalscribble">
<%= f.submit "Share",:class=>"btn btn-info" %>
</div>
</div>
<% end %>
localfeeds_controller.rb
def newlocalscribble
#localfeed = Localfeed.find_by_id(params[:localfeed])
#user = current_user
#newlocalscribble = #localfeed.scribbles.create(params[:localscribble])
##localscribble.scribbled = #user
##localscribble.scribbled = #localfeed
end
def new
#localfeed = Localfeed.new
#feed = Localfeed.find_by_id(params[:localfeed])
#newlocalscribble = #feed.scribbles.new
end
routes.rb
resources :localfeeds do
resource :scribbles
collection do
post 'localscribble', :action => :newlocalscribble
end
end
Variables passed.
{"utf8"=>"✓",
"authenticity_token"=>"1+/Qu/o4EeEbpiL/g07XFa3756IQDo6ldmKH196EkSQ=",
"scribble"=>{"post"=>"hfdfs",
"localfeed"=>"1"},
"commit"=>"Share"}
most likely your variable params[:localfeed] is not set right. It is either nil or the value that came in is not in the database.
Solved It by passing the :locals => {:scribble => #scribble, :localfeed => #localfeed} to pass the right feed ID params to partial, and deleted the hidden field which created a duplicate and cause mass assignment error
Thank you Guys

Rails model - how to differentiate different types

I am currently working on a nested model form.
I have a subject model.
This subject model has lessons of 3 different types - tutorial, lecture and laboratory.
I am able to get the nested form working with https://github.com/ryanb/nested_form.
But I want to fix it such that in the form only 3 forms for the child(lesson model) will be produced and that their first field (lesson_type field) will be automatically filled in and fixed.
I am not too sure on how to model such a situation on Rails.
These are the codes I have so far.
Any advice on what I could try out or point out the mistakes I have made would be appreciated.
This is the form.
Right now I could get the form to show up three times on my controller but I am not sure how I could generate different values for the fields. They are all showing lecture as of now.
<%= nested_form_for(#subject, :remote=>true) do |f| %>
<div class="field">
<%= f.label :subject_code %><br />
<%= f.text_field :subject_code %>
</div>
<%= f.fields_for :lessons do |lesson_form| %>
<%= lesson_form.label :lesson_type %><br/>
<%= lesson_form.text_field :lesson_type, :value=> "lecture"%><br/>
<%= lesson_form.label :name %><br/>
<%= lesson_form.text_field :name %><br/>
<%= lesson_form.fields_for :lesson_groups do |lesson_group_form| %>
<%= lesson_group_form.label :group_index %><br/>
<%= lesson_group_form.text_field :group_index %>
<%= lesson_group_form.link_to_remove "Remove this task" %>
<% end %>
<p><%= lesson_form.link_to_add "Add a lesson_group",:lesson_groups,:id=>"open-lesson"%></p>
<% end %>
<% end %>
This is the controller. The creation will happen on the index page.
def index
#subjects = Subject.all
#subject = Subject.new
lecture = #subject.lessons.build
lecture.lesson_groups.build
lecture.destroy
tutorial = #subject.lessons.build
tutorial.lesson_groups.build
tutorial.destroy
laboratory = #subject.lessons.build
laboratory.lesson_groups.build
laboratory.destroy
respond_to do |format|
format.html # index.html.erb
format.json { render json: #subjects }
format.js
end
end
The subject model
class Subject < ActiveRecord::Base
attr_accessible :subject_code, :lessons_attributes
has_many :lessons, :dependent => :destroy
accepts_nested_attributes_for :lessons, :allow_destroy => :true, :reject_if => lambda { |a| a[:lesson_type].blank? }
end
And the lesson model
class Lesson < ActiveRecord::Base
belongs_to :subject
attr_accessible :lesson_type, :name, :subject, :lesson_groups_attributes
has_many :lesson_groups, :dependent => :destroy
accepts_nested_attributes_for :lesson_groups, :allow_destroy => true
end
Okay, I am not sure if this is to the Rails convention but I got it working according to what I want. Added the following lines in the subject model: Basically assigning the lesson type field in the model.
lecture = #subject.lessons.build
lecture.lesson_type = "lecture"
lecture.lesson_groups.build
lecture.destroy
tutorial = #subject.lessons.build
tutorial.lesson_type = "tutorial"
tutorial.lesson_groups.build
tutorial.destroy
laboratory = #subject.lessons.build
laboratory.lesson_type = "laboratory"
laboratory.lesson_groups.build
laboratory.destroy
And to make it such that they can't change the lesson type I made it read only
<%= lesson_form.text_field :lesson_type, :readonly=>true%><br/>

Rails 3.1: Nested attributes won't save through the form

I suspect this might be a very simple mistake but I've spent 3 hours looking for it so I thought I might ask for some help from the community.
I'm running through Ryan Bates' excellent screencasts on Nested Models Forms and trying to apply them to my own project. The problem is the nested attribute doesn't seem to save using the form. I can get it to save through the console but it only shows up as empty brackets when going through the form.
Here's the relevant code:
The form view (using haml)
= form_for(#article) do |f|
- if #article.errors.any?
#error_explanation
%h2
= pluralize(#article.errors.count, "error")
prohibited this article from being saved:
%ul
- #article.errors.full_messages.each do |msg|
%li= msg
.field
= f.label :title
%br/
= f.text_field :title
.field
= f.label :intro
%br/
= f.text_area :intro
= f.fields_for :subsections do |builder|
= render 'subsections_fields', :f => builder
.field
= f.label :published_at
%br/
= f.text_field :published_at
.actions
= submit_or_cancel(f)
subsection_fields form view
= f.label :header
%br/
= f.text_field :header
= f.label :order_id
= f.number_field :order_id
%br/
= f.label :body
%br/
= f.text_area :body
%br/
= f.check_box :_destroy
= f.label :_destroy, "Remove Subsection"
%br/
Controller
class ArticlesController < ApplicationController
def new
#article = Article.new
3.times { #article.subsections.build }
end
def create
#article = Article.new(params[:article])
if #article.save
flash[:notice] = "Successfully created article."
redirect_to #article
else
render :action => 'new'
end
end
def edit
#article = Article.find(params[:id])
end
def update
#article = Article.find(params[:id])
if #article.update_attributes(params[:article])
flash[:notice] = "Successfully updated article."
redirect_to #survey
else
render :action => 'edit'
end
end
def destroy
Article.find(params[:id]).destroy
flash[:notice] = "Succesfully destroy article."
redirect_to articles_url
end
def show
#article = Article.find(params[:id])
end
def index
#articles = Article.all
end
end
And the models
class Article < ActiveRecord::Base
attr_accessible :title, :intro
has_many :subsections, :dependent => :destroy
accepts_nested_attributes_for :subsections, :reject_if => lambda { |a| a[:body].blank? },
:allow_destroy => true
has_and_belongs_to_many :categories
validates :title, :presence => true
end
class Subsection < ActiveRecord::Base
attr_accessible :header, :body, :order_id
belongs_to :article
validates :header, :presence => true
validates :body, :presence => true
end
Any help figuring this out is much appreciated.
I'm not quite sure, but try it with attr_accessible :article_id as well in your Subsection model?
Adding "attr_accessible" to a model changes the way mass assignment works in rails.
If you remove the "attr_accessible" lines in your models then all your code will work perfectly as it is.
The class method "accepts_nested_attributes_for" adds a "subsections_attributes=(value)" method to your model.
The second you add "attr_accessible" to a model you now are forced into adding extra "attr_accessible" entries for each field that you want to assign via mass assignment. i.e. when you use Article.new(params[:article]).
I hope that was clear.
I figured out the answer to this one from another question.
The answer was to set my subsections_attributes as an attr_accessible, so the above Article model should look like this (I also added published_at as an attr_accessible):
class Article < ActiveRecord::Base
attr_accessible :title, :intro, :subsections_attributes, :published_at
has_many :subsections, :dependent => :destroy
accepts_nested_attributes_for :subsections, :reject_if => lambda { |a| a[:body].blank? },
:allow_destroy => true
has_and_belongs_to_many :categories
validates :title, :presence => true
end

Rails 3.1: Polymorphic Association #commentable - how to do it right?

I am having troubles with a polymorphic association in Rails. I have an application where it should be possible to comment on different models, such as Posts, Images, Projects
Right now I just have Posts to comment on. On the start page there is an index view of the latest Posts and each Post has a small Comment form underneath to comment on via Ajax, very much like Facebook.
My models look like this:
class Post < ActiveRecord::Base
belongs_to :post_category
belongs_to :user
has_many :comments, :as => :commentable
validates_presence_of :user_id
validates_presence_of :post_category_id
validates_presence_of :title
validates_presence_of :body
end
class Comment < ActiveRecord::Base
belongs_to :user
belongs_to :commentable, :polymorphic => true
end
Now in my Comments controller I added the following method (I think I took it from railscasts or something), which I assume tries to find out the #commentable dynamically when creating an comment.
But this always returns the error undefined methodcomments' for nil:NilClass`
# find commentable (parent) item
def find_commentable
params.each do |name, value|
if name =~ /(.+)_id$/
return $1.classify.constantize.find(value) unless name == 'user_id'
end
end
nil
end
def create
#commentable = find_commentable
#comment = #commentable.comments.build(params[:comment])
if #comment.save
redirect_to #comment, :notice => 'Comment was successfully created.'
redirect_to :id => nil
else
render :action => "new"
end
end
The two things I tried in my partial were:
leaving the commentable info out of the form
= form_for [#commentable, Comment.new], :remote => true do |f|
#new_comment.add_comment
= f.hidden_field :user_id, :value => current_user.id
= f.text_field :content, :size => 55, :value => 'leave a comment...', :class => 'comment_form'
= f.submit "send"
and 2. passing the commentable_id and commentable_type
= form_for [#commentable, Comment.new], :remote => true do |f|
#new_comment.add_comment
= f.hidden_field :user_id, :value => current_user.id
= f.hidden_field :commentable_id, :value => post_id
= f.hidden_field :commentable_type, :value => 'Post'
= f.text_field :content, :size => 55, :value => 'leave a comment...', :onfocus => 'this.select()', :class => 'comment_form'
= f.submit "send"
both without luck. Any help would be highly appreciated.
the whole comments controller code is in this gist: https://gist.github.com/1334286
It seems like the commentable is not assigned correctly in the comments controller. This could have multiple reasons. Here is a setup that should work for you:
In the Posts controller, e.g. action "show":
#post = Post.find(params[:id])
In the posts/show view comments form:
= form_for [#post, #post.comments.new], :remote => true do |f|
You should be able to use your comments controller as it - but you should change the render to e.g. a redirect_to :back in the create action since the comments controller will most probably not have a "new" view on its own (it is dependent from the commentable)
Also, make sure that you have nested routes for all resources that can act as a commentable, like so:
resources :posts do
resources :comments do
end
resources :comments do
resources :comments # subomments
end
UPDATED to reflect information in the comments
Don't use #commentable in the post show view, since it's only defined in the comments controller.
Do this instead:
_comment.html.erb: (the comment partial in the post show view)
<%= form_for ([comments, #vote]), remote: true do |f| %>
posts/posts_controller.rb:
<%= form_for ([#post, #vote]), remote: true do |f| %>

Resources