I am trying to add a polling feature to the app from Hartl's Rails Tutorial. Started off by following #196 Nested Model Form and Nested forms with Rails 4.2 Strong Parameters. After submitting the form, the content saves properly to the database, however, I am unable to see the results in the show page and cannot figure out why.
Models-
class Micropost < ActiveRecord::Base
has_many :polls, dependent: :destroy
accepts_nested_attributes_for :polls, :reject_if => lambda {|a| a[:content].blank? }
def questions_for_form
collection = polls.where(micropost_id: id)
collection.any? ? collection : polls.build
end
end
class Poll < ActiveRecord::Base
belongs_to :micropost
has_many :answers, dependent: :destroy
accepts_nested_attributes_for :answers, :reject_if => lambda {|a| a[:content].blank? }
def answers_for_form
collection = answers.where(micropost_id: id)
collection.any? ? collection : answers.build
end
end
class Answer < ActiveRecord::Base
belongs_to :poll
end
Controllers-
class StaticPagesController < ApplicationController
def home
if logged_in?
#micropost = current_user.microposts.build
#poll = #micropost.polls.build
3.times {#poll.answers.build}
#feed_items = current_user.feed.paginate(page: params[:page])
end
end
end
class MicropostsController < ApplicationController
def create
#micropost = current_user.microposts.build(micropost_params)
if #micropost.save
flash[:success] = "Micropost created!"
redirect_to root_url
else
#feed_items = []
render 'static_pages/home'
end
end
private
def micropost_params
params.require(:micropost).permit(:content, polls_attributes: [:content, :id, :micropost_id, answers_attributes: [:content, :id, :poll_id]])
end
end
class UsersController < ApplicationController
def show
#user = User.find(params[:id])
#microposts = #user.microposts.paginate(page: params[:page])
end
end
Routes-
Rails.application.routes.draw do
resources :microposts, only: [:create, :destroy]
resources :polls
resources :answers
end
Views-
_micropost_form.html.erb
<%= form_for(#micropost) do |f| %>
<%= render 'shared/error_messages', object: f.object %>
<div class="field">
<%= f.text_area :content, placeholder: "Compose new post..." %>
</div>
<button type="button" class="btn btn-default btn-xs" data-toggle="collapse" data-target="#pollcollapse" id="pollbtn">Poll</button>
<div id="pollcollapse" class="collapse">
<%= f.fields_for :polls do |questions_for_form| %>
<%= render 'shared/poll_fields', :f => questions_for_form %>
<% end %>
</div>
<%= f.submit "Post", class: "btn btn-primary" %>
<% end %>
_poll_fields.html.erb
<div class="field">
<%= f.text_field :content, placeholder: "Poll question..." %>
</div>
<%= f.fields_for :answers do |answers_for_form| %>
<%= render 'shared/answer_fields', :f => answers_for_form %>
<% end %>
_answer_fields.html.erb
<div>
<%= f.text_field :content, placeholder: "Answer" %>
</div>
show.html.erb
<% provide(:title, #user.name) %>
<div class="row">
<aside class="col-md-4">
<section class="user_info">
<h1>
<%= gravatar_for #user %>
<%= #user.name %>
</h1>
</section>
</aside>
<div class="col-md-8">
<% if #user.microposts.any? %>
<h3>Posts (<%= #user.microposts.count %>)</h3>
<ol class="microposts">
<%= render #microposts %>
</ol>
<%= will_paginate #microposts %>
<% end %>
</div>
</div>
_micropost.html.erb
<li id="micropost-<%= micropost.id %>">
<span class="content"><%= micropost.content %></span>
<span>
<% for poll in #micropost.polls %> //Poll & answer content do not appear.
<%= poll.content %>
<% for answer in poll.answers %>
<%= answer.content %>
<% end %>
<% end %>
</span>
</li>
I think this should be all of the relevant information, but please let me know if I am missing anything. Thank you very much for any help at all!
In your _micropost.html.erb partial, you reference #micropost which doesn't appear to be defined anywhere. Try changing that from an instance variable to tbe local variable micropost (learn about the difference between #micropost and micropost here). Also, in Ruby it's recommended by people smarter than me (at least I've read it multiple times) that you should use .each instead of for. The updated code in your partial:
<li id="micropost-<%= micropost.id %>">
<span class="content"><%= micropost.content %></span>
<span>
<% micropost.polls.each do |poll| %>
<%= poll.content %>
<% poll.answers.each do |answer| %>
<%= answer.content %>
<% end %>
<% end %>
</span>
</li>
Also, since you define #microposts in your show action, you can refactor your code in the show view like so:
<div class="col-md-8">
<% if #microposts.any? %>
<h3>Posts (<%= #microposts.count %>)</h3>
<ol class="microposts">
<%= render #microposts %>
</ol>
<%= will_paginate #microposts %>
<% end %>
</div>
Yes instance vs. Local variables issue. I'd say it might be easier to use a gen, but if you are learning rails and you have the time, my opinion is its better to do it yourself the first time. It helps you learn the framework and better able to solve problems when you run into something for which there is no gem. After learning yourself, go with a gem if you find it really serves your purpose... Or make your own gem! Cheers.
Related
First, sorry for my english,
I'm make a forum from scratch and I'm currently having an issue when I generate the post form
Showing D:/Lab/Rails/Forum/app/views/forumposts/_form.html.erb
undefined method `forumposts' for nil:NilClass
Model forumtopic.rb
belongs_to :forumforum
has_many :forumposts, :dependent => :destroy
belongs_to :user
Model forumpost.rb
belongs_to :forumtopic
belongs_to :user
forumposts_controller.rb
def create
#topic = Forumtopic.friendly.find(params[:forumtopic_id])
#forumpost = #topic.forumposts.create(params.require('forumpost').permit(:content))
if #forumpost.save
redirect_to forumtopic_path(#topic)
else
render 'new'
end
end
Views/forumposts/_form.html.erb
<% if signed_in? %>
<div class="wrapper">
<div class="post_form">
<%= simple_form_for([#topic, #topic.forumposts.build]) do |f| %>
<div>
<%= f.text_area :content, class: "post-textarea", placeholder: "Message", cols: 50, rows: 4 %>
</div>
<div>
<%= f.submit "Save ", class: "post-button" %>
</div>
<% end %>
</div>
</div>
<% end %>
views/forumtopics/show.html.erb
<div class="row">
<div class="col-md-12">
<div class="answer"> <%= #forum_topic.forumposts.count %> answers </div> **OK**
</div>
</div>
<%= render #forum_topic.forumposts %> **OK**
<% render 'forumposts/form' %> **Problem**
When I do that in console, I get all the topic's post:
#topic = Forumtopic.first
#topic.forumposts
Please help
thank you
In forumposts_controller.rb you should have action new with tne next code:
def new
#topic = Forumtopic.friendly.find(params[:forumtopic_id])
end
I have a problem with my Rails blogging engine. Overall, the registration and creation of posts works (they form in the SQLite database), however when I attempt to list all the posts a user created, it throws a NoMethodError in User's show.html.erb view: undefined method 'title'.
PostsController.rb
class PostsController < ApplicationController
before_action :user_is_required, only: [:create, :destroy]
def index
#posts = Post.all
end
def new
#post = Post.new
end
def create
#post = user_logged_in.posts.create(post_params)
if #post.save
flash[:success] = "Your post has been successfully saved."
redirect_to root_path
else
flash[:danger] = "Oops! Something went wrong. Try again."
redirect_to new_post_path
end
end
def edit
end
def update
if #post.update_attributes(post_params)
flash[:success] = "Your post has been successfully updated."
redirect_to post_path(#posts)
else
flash[:danger] = "Oops! Something went wrong. Try again."
render 'post'
end
end
def show
#post = Post.find(params[:id])
end
def destroy
if #post.destroy
flash[:success] = "Your post has been successfully deleted."
redirect_to posts_path
else
flash[:danger] = "Oops! Something went wrong. Try again."
end
end
private
def post_params
params.require(:post).permit(:title, :content)
end
end
show.html.erb (User's view)
<div class="posts">
<div class="container marketing">
<div class="col-lg-4 col-md-4 col-xs-12 col-sm-12">
<section id="info">
<%= image_tag("#", :class => "user_avatar") %>
<h2 class="user_name">
<%= user_logged_in.name %>
</h2>
</section>
<% if user_logged_in %>
<%= link_to "Change avatar", class: "btn btn-primary" %><br>
<% end %>
<%= link_to "Follow", class: "btn btn-primary" %>
</div>
<div class="col-lg-8 col-md-8 col-sm-12 col-xs-12">
<h2>
<%= user_logged_in.name %> has <%= user_logged_in.posts.count %> posts.
</h2>
<% if user_logged_in.posts.any? %>
<% #posts.each do |post| %>
<h2 class="title">
<%= user_logged_in.posts.title %> # The line which raises the error
</h2>
<p class="post">
<%= user_logged_in.posts.content %>
</p>
<% end %>
<% end %>
</div>
</div>
post.rb
class Post < ActiveRecord::Base
belongs_to :user
default_scope -> { order(created_at: :desc) }
validates :user_id, presence: true
validates :title, presence: true
validates :content, presence: true
end
I am a newbie in Ruby on Rails and this is my first project. Any and all help will be highly appreciated.
Thanks in advance.
Think the logic is a bit confused here.
user_logged_in.posts is a relation, so it returns the posts associated with the user that's logged in.
#posts is set t all the posts in the table.
<% if user_logged_in.posts.any? %>
<% #posts.each do |post| %>
<h2 class="title">
<%= user_logged_in.posts.title %> # The line which raises the error
</h2>
<p class="post">
<%= user_logged_in.posts.content %>
</p>
<% end %>
<% end %>
This says that if the logged in user has any posts, loop through all of the posts (not just the users posts), and then I think you want to display the users posts, but you're going wrong with syntax. Try changing your code as follows:
<% if user_logged_in.posts.any? %>
<% user_logged_in.posts.each do |post| %>
<h2 class="title">
<%= post.title %>
</h2>
<p class="post">
<%= post.content %>
</p>
<% end %>
<% end %>
This will loop through the users posts, assigning each post to the post variable, and then displaying the title and content of that post.
posts should be post as you are inside loop i.e <%= user_logged_in.posts.title %> should be <%= post.title %> :
<% #posts.each do |post| %>
<h2 class="title">
<%= post.title %> # The line which raises the error
</h2>
<p class="post">
<%= post.content %>
</p>
<% end %>
when i click new post and try to save a new post it gives me that error, then i go to the controller :
private
def posts_params
params.require(:post).permit(:title, :description)
end
and change 'require(:post)' to 'require(:posts' then i works
but then i try to edit the new post i just created and when i click to save it it gives me the same error, then i just change it back to 'required(:post)' and it works, why this is happening ? it's like a loop, if one works the other doesn't and to work i have to change that one thing
Controller:
class PostsController < ApplicationController
def index
#posts = Post.all
end
def edit
#posts = Post.find(params[:id])
end
def update
#posts = Post.find(params[:id])
if #posts.update(posts_params)
redirect_to #posts
else
render 'edit'
end
end
def new
#posts = Post.new
end
def create
#posts = Post.new(posts_params)
if #posts.save
redirect_to #posts
else
render 'new'
end
end
def show
#posts = Post.find(params[:id])
end
private
def posts_params
params.require(:post).permit(:title, :description)
end
end
view edit:
<h1>Editing post</h1>
<%= form_for(#posts) do |f| %>
<% if #posts.errors.any? %>
<div id="error_explanation">
<h2>
<%= pluralize(#posts.errors.count, "error") %> prohibited
this post from being saved:
</h2>
<ul>
<% #posts.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<p>
<%= f.label :title %><br>
<%= f.text_field :title %>
</p>
<p>
<%= f.label :description %><br>
<%= f.text_area :description %>
</p>
<p>
<%= f.submit %>
</p>
<% end %>
<%= link_to 'Back', posts_path %>
view new:
<h1>New Article</h1>
<%= form_for :posts, url: posts_path do |f| %>
<% if #posts.errors.any? %>
<div id="error_explanation">
<h2>
<%= pluralize(#posts.errors.count, "error") %> prohibited
this post from being saved:
</h2>
<ul>
<% #posts.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<p>
<%= f.label :title %><br>
<%= f.text_field :title %>
</p>
<p>
<%= f.label :description %><br>
<%= f.text_area :description %>
</p>
<p>
<%= f.submit %>
</p>
<% end %>
<%= link_to 'Back', posts_path %>
can someone point the problem out ?
You are mixing
form_for(#posts) do |f|
and
form_for :posts, url: posts_path
In your forms.
the :posts version will generate params[:posts] and the #posts version will generate params[:post]. Hence the issue you are seeing. Make sure you posts_params is as follows.
def posts_params
params.require(:post).permit(:title, :description)
end
then just change both of your forms to be
<%= form_for(#posts) do |f| %>
rails will figure out which to call automatically for you, so you will not have to specify the paths..
On a side note, I would probably change #posts to be #post everywhere but the index action, just so that it makes more sense, Since in new,edit,etc.. you are dealing with a singular post.
Since rails is looking at the Model/class of the variable when generating the routes (When given an instance variable) the name of the variable doesn't matter to the framework, but makes it easier (in my opinion) for the programmer to understand
I am new to Ruby on Rails. My Question might sound weird, but i am stuck. i have a form Create that is on html page. i used render partial, but this form is not creating any value. here is my controller code.
Controller.rb
before_filter :signed_in_user, only: [:create, :destroy]
def create
#suppliers = current_user.suppliers.build(params[:supplier_name])
if #suppliers.save
flash[:success] = "Supplier Saved!"
redirect_to 'suppliers/home'
else
render 'suppliers/home'
end
end
def destroy
end
def home
if signed_in?
#supplier = current_user.suppliers.build
#feed_items = current_user.feed.paginate(page: params[:page])
end
end
my home.html.erb
<div class="row">
<aside class="span4">
<section>
<%= render 'suppliers/suppliers_form' %>
</section>
</aside>
<div class="span8">
<h3>Micropost Feed</h3>
<%= render 'suppliers/feed_supplier' %>
</div>
</div>
My _supplier_form.html.erb is
<%= form_for(#supplier) do |f| %>
<div>
<%= f.text_field :supplier_name, placeholder: "Add new Supplier" %>
</div>
<%= f.submit "Add", class: "btn btn-large btn-primary" %>
<% end %>
My _feed_supplier.html.erb is
<% if #feed_items.any? %>
<ol class="microposts">
<%= render partial: 'suppliers/feed_item', collection: #feed_items %>
</ol>
<%= will_paginate #feed_items %>
<% end %>
my _feed_item.html.erb is
<li id="<%= feed_item.id %>">
<span class="user">
<%= link_to feed_item.user.name, feed_item.user %>
</span>
<span class="content"><%= feed_item.supplier_name %></span>
</li>
please guide me to right direction, and if anything else is required then do ask. Thanks in advance
Note: all the mentioned files are in same folder i.e. suppliers. except the controller file
form_for #supplier
will create a parameter hash like
{ :supplier => { :supplier_name => '[some value you put in your form]' }}
so the create action should use
#suppliers = current_user.suppliers.build(params[:supplier])
There is no params[:supplier_name].
I think for the partials, you don't need to write suppliers/*, for example:
<%= render 'suppliers/suppliers_form' %>
could just be
<%= render 'suppliers_form' %>
not sure why that would be causing your app to do what it's doing, but worth a try!
I develop site which has articles and news pages and I would like to add opportunity to comment both. I use polymorphic associations.
class Article < ActiveRecord::Base
has_many :commentaries, :as => :commentable
end
class News < ActiveRecord::Base
has_many :commentaries, :as => :commentable
end
class Commentary < ActiveRecord::Base
belongs_to :commentable, :polymorphic => true
end
I would like to show comments below commentable object
views/articles/show.html.erb
<p>
<b>Title:</b>
<%= #article.title %>
</p>
<p>
<b>Short text:</b>
<%= #article.short_text %>
</p>
<p>
<b>Full text:</b>
<%= #article.full_text %>
</p>
<%= render 'commentaries/form' %>
views/news/show.html.erb
<p>
<b>Title:</b>
<%= #news.title %>
</p>
<p>
<b>Text:</b>
<%= #news.text %>
</p>
<p>
<b>Created:</b>
<%= #news.created %>
</p>
views/commentaries/_form.html.erb
<h1>Comments</h1>
<ul id="comments">
<% #commentaries.each do |comment| %>
<li><%= comment.content %></li>
<% end %>
</ul>
<h2>New Comment</h2>
<% form_for [#commentable, Comment.new] do |form| %>
<ol class="formList">
<li>
<%= form.label :content %>
<%= form.text_area :content, :rows => 5 %>
</li>
<li><%= submit_tag "Add comment" %></li>
</ol>
<% end %>
And my controllers:
class CommentariesController < ApplicationController
def index
#commentable = find_commentable
#commentaries = #commentable.commentaries
end
end
class ArticlesController < ApplicationController
def show
#article = Article.find(params[:id])
end
end
When I go to mysite/article/1 I get error undefined method `each' for nil:NilClass, because there isn't #commentable in my article controller and commentaries controller's code doesn't execute.
How to execute index action of commentaries controller on article/show page?
Add local variable:commentable => #article, while rendering the commentaries form
<%= render 'commentaries/form', :commentable => #article %>
Access the local variable from you partial view views/commentaries/_form.html.erb
<% commentable.commentaries.each do |comment| %>
...
<% end %>
...
<% form_for [commentable, Comment.new] do |form| %>
...
<% end %>