How to link to a nested route action inside a parent loop? - ruby-on-rails

I'm trying to display everything on my index page, but when I try to link to a new_story_substory_path I get undefined local variable or method substory.
Here is the code:
index.html.erb
<% #stories.each do |story| %>
<h3><p><%= story.title %></p></h3>
<p><%= story.plot %></p>
<% if story.user == current_user %>
<%= link_to 'Show XXX', story_path(story), class: "btn btn-success" %>
<%= link_to 'Edit', edit_story_path(story), class: "btn btn-success" %>
<%= link_to "Delete", story_path(story), method: :delete, data: { confirm: "Are you sure?" }, class: "btn btn-success" %></br>
<% end %>
<% story.substories.each do |substory| %>
<h4><p><%= substory.title %></p></h3>
<p><%= substory.subplot %></p>
<% if story.user == current_user %>
<%= link_to 'Show', story_substory_path(substory.story, substory), class: "btn btn-default" %>
<%= link_to 'Edit', edit_story_substory_path(substory.story, substory), class: "btn btn-default" %>
<%= link_to "Delete", story_substory_path(substory.story, substory), method: :delete, data: { confirm: "Are you sure?" }, class: "btn btn-default" %>
<% end %>
<% end %>
<br>
<% if story.user == current_user %>
<br>
<br>
# this is where I'm getting the error:
<%= link_to 'New subplot', new_story_substory_path(substory.story, substory), class: "btn btn-warning" %>
# however if I move this up, inside the second loop, it works perfectly.
<br>
<% end %>
<% end %>
<br>
<%= link_to 'New Story', new_story_path, class: "btn btn-danger" %>
Here is my controller, routes and models:
class StoriesController < ApplicationController
before_action :set_story, only: [:show, :edit, :update, :destroy]
before_action :authenticate_user!, except: [:index, :show]
def index
#stories = Story.all
end
def show
end
def new
#story = current_user.stories.build
end
def edit
end
def create
#story = current_user.stories.build(story_params)
respond_to do |format|
if #story.save
format.html { redirect_to root_path, notice: 'Story was successfully created.' }
format.json { render :show, status: :created, location: root_path }
else
format.html { render :new }
format.json { render json: root_path.errors, status: :unprocessable_entity }
end
end
end
def update
respond_to do |format|
if #story.update(story_params)
format.html { redirect_to root_path, notice: 'Story was successfully updated.' }
format.json { render :show, status: :ok, location: root_path }
else
format.html { render :edit }
format.json { render json: #story.errors, status: :unprocessable_entity }
end
end
end
def destroy
#story.destroy
respond_to do |format|
format.html { redirect_to stories_url, notice: 'Story was successfully destroyed.' }
format.json { head :no_content }
end
end
private
def set_story
#story = Story.find(params[:id])
end
def story_params
params.require(:story).permit(:title, :plot)
end
end
Rails.application.routes.draw do
devise_for :users
resources :stories do
resources :substories
end
root 'stories#index'
end
class Story < ActiveRecord::Base
has_many :substories, dependent: :destroy
belongs_to :user
end
class Substory < ActiveRecord::Base
belongs_to :story
belongs_to :user
end
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
has_many :stories, dependent: :destroy
has_many :substories, dependent: :destroy
end
what am I missing?
Edit:
Here is the controller for the substories:
class SubstoriesController < ApplicationController
before_action :set_substory, only: [:show, :edit, :update, :destroy]
before_action :authenticate_user!
before_action :set_story
def index
#Substories = #story.substories.all
end
def show
end
def new
#substory = Substory.new
end
def edit
end
def create
#substory = Substory.new(substory_params)
#substory.user_id = current_user.id
#substory.story_id = #story.id
if
#substory.save
redirect_to #story
else
render 'new'
end
end
def update
respond_to do |format|
if #substory.update(substory_params)
format.html { redirect_to root_path, notice: 'Story was successfully updated.' }
format.json { render :show, status: :ok, location: root_path }
else
format.html { render :edit }
format.json { render json: #story.errors, status: :unprocessable_entity }
end
end
end
def destroy
#substory.destroy
redirect_to root_path
end
private
def set_story
#story = Story.find(params[:story_id])
end
def set_substory
#substory = Substory.find(params[:id])
end
def substory_params
params.require(:substory).permit(:title, :subplot)
end
end

I am trying to put this as a comment but I need 50 reputation points to do so. Anyway here is my solution:
The problem is index.html comes from Stories Controller. At this point, you are actually not using any other controllers. This is a common problem at a single page application using ROR. Things do get messy this way.
And you are right, you have to move your error on the second loop. The problem is it would show more than once. That is because there is more than one story. If you want to avoid this, the solution I would say is just make an stories#show show.html.erb. Once you click story, it directs to substroy which then has a plot.

I got the answer from the comments.
MrYoshi wrote:
At the line producing the error: You are calling the substory variable but it is only existing in the story.substories.each loop ; you probably meant to use new_story_substory_path(story) (path leading to the creation page of a substory belonging to the story currently been seen/edited)
Basically I changed the line form:
<%= link_to 'New subplot', new_story_substory_path(substory.story, substory), class: "btn btn-warning" %>
to:
<%= link_to 'New subplot', new_story_substory_path(story), class: "btn btn-warning" %>
This works!

Related

rails - if condition on view - undefined method `id' for nil:NilClass

I have a class called #Subdomain:
Here is my controller:
class SubdomainsController < ApplicationController
before_action :authenticate_user!, only: [:edit, :update]
before_action :set_subdomain, only: [:show, :edit, :update, :destroy]
before_action :redirect_to_subdomain, only: :show
before_action :redirect_to_subdomain_show, only: :root, unless: '#subdomain.nil?'
def root
render nothing: true
end
def index
#subdomains = Subdomain.all
end
def show
end
def new
#subdomain = Subdomain.new
end
def edit
end
def create
#subdomain = Subdomain.new(subdomain_params)
respond_to do |format|
if #subdomain.save
format.html { redirect_to #subdomain, notice: 'Subdomain was successfully created.' }
format.json { render :show, status: :created, location: #subdomain }
else
format.html { render :new }
format.json { render json: #subdomain.errors, status: :unprocessable_entity }
end
end
end
def update
respond_to do |format|
if #subdomain.update(subdomain_params)
format.html { redirect_to #subdomain, notice: 'Subdomain was successfully updated.' }
format.json { render :show, status: :ok, location: #subdomain }
else
format.html { render :edit }
format.json { render json: #subdomain.errors, status: :unprocessable_entity }
end
end
end
def destroy
#subdomain.destroy
respond_to do |format|
format.html { redirect_to subdomains_url, notice: 'Subdomain was successfully destroyed.' }
format.json { head :no_content }
end
end
private
def redirect_to_subdomain_show
redirect_to subdomain_url(#subdomain) if #request_subdomain.eql? #subdomain.address
end
# Redirect to subdomain... if the current one isn't equal to #subdomain.address column
def redirect_to_subdomain
redirect_to subdomain_url(#subdomain, subdomain: #subdomain.address) unless #request_subdomain.eql? #subdomain.address
end
def set_subdomain
#subdomain = Subdomain.find(params[:id])
end
def subdomain_params
#subdomain.assign_attributes(tag_speciality: params[:subdomain][:tag_speciality].split(','))
params.require(:subdomain).permit(
:domain_id,
:address,
:title,
:description,
:is_published,
:button_text_client,
:button_text_service,
:cover,
:primary_colour,
:secundary_colour,
:contrast_colour,
:logo,
:find_clients,
:find_professional,
:start_relation,
:publications_wall,
:tag_speciality,
:cards_wall
)
end
end
On the view i created a condition:
<% if (!#subdomain.id.blank?) %>
<li>
<%= link_to cards_from_subdomain_path(subdomain_id: #subdomain.id) do %>
<i class="fa fa-search fa-lg"></i>
<span class="hidden-medium">
&nbsp <%= #subdomain.cards_wall %>
</span>
<% end %>
</li>
<li>
<%= link_to publications_from_subdomain_path(subdomain_id: #subdomain.id) do %>
<i class="icon-grid fa-lg"></i>
<span class="hidden-medium">
&nbsp <%= #subdomain.publications_wall %>
</span>
<% end %>
</li>
<% else %>
<li>Some thing</li>
<% end %>
Here is the model:
class Subdomain < ActiveRecord::Base
belongs_to :domain
has_many :cards
mount_uploader :cover, AssetsUploader
mount_uploader :logo, AssetsUploader
end
When the #subdomain exist is ok, everything works fine, but when it doesn't exist, i get this error message:
NoMethodError in Subdomains#index
undefined method `id' for nil:NilClass
<% if (!#subdomain.id.blank?) %>
What could i do to fix that? thanks
The quick and dirty solution would be to use #try (not recommended though)
<% if !#subdomain.try(:id).try(:blank?) %>
By the way, you can use #present? instead of negating a #blank? to make code more readable.
However, if I assume correctly and the #subdomain is an ActiveRecord model, you don't need to check if it's id is present. A following code should be sufficient in your case:
<% if #subdomain %>
(...)
<% else %>
(...)
<% end %>
If the #subdomain is not found, it will be a nil anyway - and then the if #subdomain condition will be evaluated as false - since nil is a falsy value.
And if you get this error because you happen to be rendering a collection like this:
= render 'subdomain', collection: #subdomains
...then you can just put that inside a condition...
<% if #subdomains.present? %>
= render 'subdomain', collection: #subdomains
<% else %>
<% # #subdomains are an empty collection %>
<% end %>
From your create action, id will definitely be created in your table. I don't still understand what you are trying to get to, for negating on #id.blank?.
Change the first line from your view. i.e.
<% if (!#subdomain.id.blank?) %>
to,
<% if #subdomains %>, which will definitely return all attributes on your Subdomain Table since its has being taken care of in your index action.
Another thing I do is wrap my if...else statement inside a loop, such the your view becomes:
<% #subdomains.each do |subd| %>
<% if subd.id.present? %> #you can use another attribute here instead of id. e.g. <% if subd.is_published == true %> since `is_published` is a boolean.
<li>
(#your codes here referenced with the format called `subd.whatever_attribute`)
</li>
<li>
(#your codes here referenced with the format called `subd.whatever_attribute`)
</li>
<% else %>
<li>Some thing</li>
<% end %>
<% end %>

How to add comments to statuses (like facebook)

I am trying to improve an exercice that I did on treehouse, the idea was to remake a little version of facebook thing, where users could publish statuses.
Now I want that a user can comment any statuses... And I am kinda lost...
The idea is to have all on the same page (if possible?, like on the real facebook)
So the comment form and the "displaying" content...
I hope anyone could help me :)
This is my github repository
I think I haven't understand how to call variables from a controller to another...
If someone could explain me with very easy words ... I am not native english speaker... so sometime it's difficult..
Here are the statuses part
controllers/statuses_controller/rb
class StatusesController < ApplicationController
before_filter :authenticate_user!, only: [:new, :create, :edit, :update]
before_action :set_status, only: [:show, :edit, :update, :destroy]
def index
#statuses = Status.all
#comments = Comment.all
end
def show
#status = Status.find(params[:id])
#comments = #status.comments.all
end
def new
#status = Status.new
#comment = #status.comments.build
end
def create
#status = Status.new(status_params)
#status.user = current_user
respond_to do |format|
if #status.save
format.html { redirect_to #status, notice: 'Status was successfully created.' }
format.json { render :show, status: :created, location: #status }
else
format.html { render :new }
format.json { render json: #status.errors, status: :unprocessable_entity }
end
end
end
def update
respond_to do |format|
if #status.update(status_params)
format.html { redirect_to #status, notice: 'Status was successfully updated.' }
format.json { render :show, status: :ok, location: #status }
else
format.html { render :edit }
format.json { render json: #status.errors, status: :unprocessable_entity }
end
end
end
def destroy
#status.destroy
respond_to do |format|
format.html { redirect_to statuses_url, notice: 'Status was successfully destroyed.' }
format.json { head :no_content }
end
end
private
def set_status
#status = Status.find(params[:id])
end
def status_params
params.require(:status).permit(:user_id, :content, :comments_attribute[:id, :status_id, :content])
end
end
models/status.rb
class Status < ActiveRecord::Base
belongs_to :user
has_many :comments
default_scope -> { order(created_at: :DESC)}
validates :content, presence: true,
length: {minimum: 2}
validates :user_id, presence: true
end
views/comments/_form.html.erb I create a render in my index below:
<% simple_form_for #status.comments do |f|%>
<%= f.input :content %>
<%= f.button :submit %>
<% end %>
view/statuses/index.html.erb
<div class="page-header">
<h1>All of the Statuses</h1>
</div>
<%= link_to "Post A New Status", new_status_path, class: "btn btn-success"%>
<br>
<br>
<% #statuses.each do |status| %>
<div class="status">
<div class="row">
<div class="col-xs-1 avatar">
<%= image_tag status.user.avatar.thumb if status.user.avatar?%>
</div>
<div class="col-xs-7">
<h4><%= status.user.full_name%></h4>
</div>
</div>
<div class="row">
<div class="col-xs-8">
<p><%= simple_format(status.content) %></p>
</div>
</div>
<div class="row">
<div class="col-xs-8">
<%= link_to time_ago_in_words(status.created_at) + " ago", status %>
<% if status.user == current_user %>
<span class="admin">
| <%= link_to "Edit", edit_status_path(status) %> |
<%= link_to "Delete", status, method: :delete, data: {confirm: "Are you sure?"} %>
</span>
<% end %>
</div>
</div>
<div class="row">
<div class="col-xs-12">
<p>Comments</p>
<% #comments.each do |comment| %>
<%= comment.content %>
<% end %>
</div>
</div>
<div class="row">
<div class="col-xs-12">
<%= render "comments/form" %>
</div>
</div>
</div>
Now the comments part:
model/comment.rb
class Comment < ActiveRecord::Base
belongs_to :status
belongs_to :user
end
controllers/comments_controller.rb
class CommentsController < ApplicationController
def create
#comment = Comment.new(params_comment)
end
def index
#statuses = Status.all
#comments = Comment.all
#comment = Comment.find_by(params[:id])
end
private
def params_comment
params.require(:comment).permit(:content)
end
end
routes.rb
resources :statuses do
resources :comments
end
user.rb
that's a part of what I have in there
has_many :statuses
has_many :comments
your comments creation method should look like this:
#status = Status.find(params[:status_id])
#comment = #status.comments.create(comment_params)
#comment.user_id = current_user.id if current_user
#comment.save

Deleting Nested Reviews Deletes the whole Post Created

I am setting a nested review scaffold inside the Post scaffold however, when i try to delete a review that is nested inside the show page in the Post, The whole post is deleted. how can i delete only the reviews without the post?
here's my code:
posts_controller.rb
class PostsController < ApplicationController
before_action :set_post, only: [:show, :edit, :update, :destroy]
before_action :authenticate_user! , except: [:index,:show]
before_filter :check_user, only: [:edit,:update,:destroy]
# GET /posts
# GET /posts.json
def search
if params[:search].present?
#posts = Post.search(params[:search])
else
#posts = Post.all
end
end
def index
if params[:tag]
#posts = Post.tagged_with(params[:tag])
else
#posts = Post.all
end
end
# GET /posts/1
# GET /posts/1.json
def show
#reviews = Review.where(post_id: #post.id)
end
# GET /posts/new
def new
#post = Post.new
end
# GET /posts/1/edit
def edit
#post = Post.find(params[:id])
end
# POST /posts
# POST /posts.json
def create
#post = Post.new(post_params)
#post.user_id = current_user.id
respond_to do |format|
if #post.save
format.html { redirect_to #post, notice: 'Post was successfully created.' }
format.json { render :show, status: :created, location: #post }
else
format.html { render :new }
format.json { render json: #post.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /posts/1
# PATCH/PUT /posts/1.json
def update
respond_to do |format|
if #post.update(post_params)
format.html { redirect_to root_url, notice: 'Post was successfully updated.' }
format.json { render :show, status: :ok, location: #post }
else
format.html { render :edit }
format.json { render json: #post.errors, status: :unprocessable_entity }
end
end
end
# DELETE /posts/1
# DELETE /posts/1.json
def destroy
#post.destroy
respond_to do |format|
format.html { redirect_to posts_url, notice: 'Post was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_post
#post = Post.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def post_params
params.require(:post).permit(:title, :description,:image,:all_tags)
end
def check_user
if current_user.id != #post.user_id
redirect_to root_path , alert: "Sorry this Post belongs to someone else"
end
end
end
routes.rb
Rails.application.routes.draw do
devise_for :users
resources :posts do
collection do
get 'search'
end
resources :reviews , except: [:show,:index] do
member do
get "like" => "reviews#upvote"
get "dislike" => "reviews#downvote"
end
end
end
get 'pages/help'
get 'pages/blog'
get 'pages/contact'
get 'pages/tour'
resources :posts
root 'posts#index'
get 'tags/:tag', to: 'posts#index', as: "tag"
end
reviews_controller.rb
class ReviewsController < ApplicationController
before_action :set_review, only: [ :edit, :update, :destroy, :upvote,:downvote]
before_action :set_post
before_action :authenticate_user!
respond_to :html
def new
#review = Review.new
respond_with(#review)
end
def edit
end
def create
#review = Review.new(review_params)
#review.user_id = current_user.id
#review.post_id = #post.id
#review.save
redirect_to post_path(#post)
end
def update
#review.update(review_params)
respond_with(#post)
end
def destroy
#review.destroy
respond_with(#review)
end
def upvote
#review.upvote_from current_user
redirect_to :back
end
def downvote
#review.downvote_from current_user
redirect_to :back
end
private
def set_review
#review = Review.find(params[:id])
end
def set_post
unless #post = Post.where(id: params[:post_id]).first
redirect_to posts_path, flash: {alert: "Post doesn't exists"}
end
end
def review_params
params.require(:review).permit(:comment)
end
end
models/review.rb
class Review < ActiveRecord::Base
acts_as_votable
belongs_to :user
belongs_to :post
end
models/post.rb
class Post < ActiveRecord::Base
searchkick
has_many :reviews , dependent: :destroy
has_many :taggings
has_many :tags, through: :taggings
#Paperclip Installation
has_attached_file :image, styles: { medium: "300x300>", thumb: "100x100>" }, default_url: "/images/:style/missing.png"
validates_attachment_content_type :image, :content_type => ["image/jpg", "image/jpeg", "image/png", "image/gif"]
def all_tags=(names)
self.tags = names.split(",").map do |name|
Tag.where(name: name.strip).first_or_create!
end
end
def all_tags
self.tags.map(&:name).join(", ")
end
def self.tagged_with(name)
Tag.find_by_name!(name).posts
end
end
views/posts/index.html.erb
<table class="table">
<thead>
<tr>
<th colspan="3"></th>
</tr>
</thead>
<tbody>
<% #posts.each do |post| %>
<tr>
<td><h4><%=link_to post.title , post%></h4></td>
<td><%=raw tag_links(post.all_tags)%></td>
<td><%= link_to 'Edit', edit_post_path(post) %></td>
<td><%= link_to 'Destroy', post, method: :delete, data: { confirm: 'Are you sure?' } %></td>
</tr>
<%end%>
</tbody>
</table>
<%= link_to 'new post', new_post_path %>
views/posts/show.html.erb
<div class="center">
<div class="right-align">
<h2><%= #post.title %></h2>
<hr>
</div>
<%if #post.image.exists?%>
<%= image_tag #post.image.url(:medium) %>
<%end%>
<div class="right-align">
<%= markdown #post.description %>
<br>
<table class="table table-bordered">
<tbody>
<% #reviews.each do |review|%>
<tr>
<td >
Welcome back <%= current_user.name %>
<h4><%= link_to "like" ,like_post_review_path(#post, review) , class: " btn btn-primary glyphicon glyphicon-chevron-up"%></h4>
<p><%= review.get_upvotes.size%></p>
<p><%= review.get_downvotes.size%></p>
<h4><%= link_to "Dislike" , dislike_post_review_path(#post, review) , class: "btn btn-primary glyphicon glyphicon-chevron-down"%></h4>
<p><%= markdown review.comment %></p>
<p><%= link_to "Edit", edit_post_review_path(#post, review) %></p>
<p><%= link_to 'Destroy', #review, method: :delete, data: { confirm: 'Are you sure?' } %></p>
</td>
</tr>
<%end%>
</tbody>
</table>
<p><%= link_to 'Write Review', new_post_review_path(#post) , class: "btn btn-primary" %></p>
<%= link_to 'Edit', edit_post_path(#post) %> |
<%= link_to 'Back', posts_path %>
</div>
</div>
Update:
i tried changing the code as suggested in the destroy method and in the Reviews Controller and the Post Show page but still getting the error. Here's the error i am getting :
Look like a typo, change:
<p><%= link_to 'Destroy', #review, method: :delete, data: { confirm: 'Are you sure?' } %></p>
to:
<p><%= link_to 'Destroy', review, method: :delete, data: { confirm: 'Are you sure?' } %></p>
and change your reviews controller destroy:
def destroy
#review.destroy
redirect_to :back
end

Acts As Votable Get Upvotes Error

Working with the Acts as Votable gem on my rails 4 app.
So far I have gotten everything working, except when I call get_upvotes and get_downvotes to display how many votes a post has, I get this error:
undefined method `get_upvotes' for #<Post:0x000001078b5f58>
Here is my Post view (_post.html.erb):
<%= post.name %>
<%= post.title %>
<%= post.content %><br>
<%= link_to 'Show', post %>
<% if can? :update, #post %>
<%= link_to 'Edit', edit_post_path(post) %>
<% end %>
<% if can? :destroy, #post %>
<%= link_to 'Destroy', post, method: :delete, data: { confirm: 'Are you sure?' } %>
<% end %>
<%= link_to like_post_path(post), class: "like", method: :put do %>
<button type="button" class="btn btn-info" aria-label="Left Align">
<span class="glyphicon glyphicon-thumbs-up glyphicon-align-center" aria-hidden="true"></span>
<span class="badge"><%= post.get_upvotes.size %></span>
</button>
<% end %>
<%= link_to dislike_post_path(post), class: "like", method: :put do %>
<button type="button" class="btn btn-info" aria-label="Left Align">
<span class="glyphicon glyphicon-thumbs-down glyphicon-align-center" aria-hidden="true"></span>
<span class="badge"><%= post.get_downvotes.size %></span>
</button>
<% end %>
Here is my controller (posts_controller.rb):
class PostsController < ApplicationController
load_and_authorize_resource
before_action :set_post, only: [:show, :edit, :update, :destroy, :upvote, :downvote]
def index
end
def show
end
def new
end
def edit
end
def create
respond_to do |format|
if #post.save
format.html { redirect_to #post, notice: 'Post was successfully created.' }
format.json { render :show, status: :created, location: #post }
else
format.html { render :new }
format.json { render json: #post.errors, status: :unprocessable_entity }
end
end
end
def update
respond_to do |format|
if #post.update(post_params)
format.html { redirect_to #post, notice: 'Post was successfully updated.' }
format.json { render :show, status: :ok, location: #post }
else
format.html { render :edit }
format.json { render json: #post.errors, status: :unprocessable_entity }
end
end
end
def destroy
#post.destroy
respond_to do |format|
format.html { redirect_to posts_url, notice: 'Post was successfully destroyed.' }
format.json { head :no_content }
end
end
def upvote
#post = Post.find(params[:id])
#post.upvote_from current_user
redirect_to :back
end
def downvote
#post = Post.find(params[:id])
#post.downvote_from current_user
redirect_to :back
end
private
def set_post
#post = Post.find(params[:id])
end
def post_params
params.require(:post).permit(:name, :title, :content, :image, :image2, :video1, :video2)
end
end
and my model (post.rb):
class Post < ActiveRecord::Base
acts_as_voter
belongs_to :user
end
user model (user.rb):
class User < ActiveRecord::Base
acts_as_votable
has_many :posts
end
and lastly my routes (routes.rb):
resources :posts do
member do
put "like" => "posts#upvote"
put "dislike" => "posts#downvote"
end
end
Does anyone know why get_upvotes isn't working?
Reading the docs, it looks like get_upvotes is a method on the acts_as_votable, not the acts_as_voter.
I don't know much about the context of your code, but shouldn't the User be voting on the Post, like so:
class Post < ActiveRecord::Base
acts_as_votable
belongs_to :user
end
User model:
class User < ActiveRecord::Base
acts_as_voter
has_many :posts
end
See: https://github.com/ryanto/acts_as_votable#votable-models

Post and Location Association with ancestry gem

My Rails application have two model. Location and Post, Location have many post.I am Using
ancestry gem.
class Post < ActiveRecord::Base
belongs_to :location, :counter_cache => true
end
class Location < ActiveRecord::Base
include Tree
has_ancestry :cache_depth => true
has_many :posts
end
My Post Controller
class PostsController < ApplicationController
before_action :set_post, only: [:show, :edit, :update, :destroy]
def index
#posts = Post.all
end
def show
end
def new
#post = Post.new
end
def edit
end
def create
#post = Post.new(post_params)
respond_to do |format|
if #post.save
format.html { redirect_to #post, notice: 'Post was successfully created.' }
format.json { render action: 'show', status: :created, location: #post }
else
format.html { render action: 'new' }
format.json { render json: #post.errors, status: :unprocessable_entity }
end
end
end
def update
respond_to do |format|
if #post.update(post_params)
format.html { redirect_to #post, notice: 'Post was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: 'edit' }
format.json { render json: #post.errors, status: :unprocessable_entity }
end
end
end
def destroy
#post.destroy
respond_to do |format|
format.html { redirect_to posts_url }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_post
#post = Post.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def post_params
params.require(:post).permit(:name)
end
end
If i am create new Post with which Location belongs in _form.html.erb
<%= form_for(#post) do |f| %>
<% if #post.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#post.errors.count, "error") %> prohibited this post from being saved: </h2>
<ul>
<% #post.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :name %><br />
<%= f.text_field :name %>
</div>
<%= select :location_id, Location.all.at_depth(4) { |l| [ l.name, l.id ] } %>
<div class="actions">
<%= f.submit %>
</div>
Browser show error message which is display bellow
ArgumentError in Posts#new
Not sure if this fixes your error, but:
To make the dropdown working, change the select line to:
<%= f.select :location_id, Location.all.at_depth(4) { |l| [ l.name, l.id ] } %>
This is because you want the formbuilder f to handle the creation of the form element.
You also have to whitelist the :location_id parameter in the controller:
def post_params
params.require(:post).permit(:name, :location_id)
end

Resources