I am working on a project that a user can create a post and others can send posts about that topic.My resources file is :
resources :users
resources :sessions, only: [:new, :create, :destroy]
resources :topics , only: [ :show, :create, :destroy] do
resources :posts, only: [:create, :new]
My topics_form.html.erb:
<%= form_for(#topic) do |f| %>
<%= render 'shared/error_messages', object: f.object %>
<div class="field">
<%= f.text_area :title, placeholder: "yeni başlık girin..." %>
</div>
<%= f.submit "Gönder", class: "btn btn-large btn-primary" %>
<% end %>
my create action is :
def create
#topic = current_user.topics.build(params[:topic])
if #topic.save
flash[:success] = "Konu oluşturuldu!"
redirect_to root_path
else
render 'static_pages/home'
end
end
My posts_form.html.erb is :
<%= form_for [#topic, #post] do |f| %>
<%= render 'shared/error_messages', object: f.object %>
<div class="field">
<%= f.text_area :content, placeholder: "yorumunuzu girin..." %>
</div>
<%= f.submit "Gönder", class: "btn btn-large btn-primary" %>
<% end %>
my post_controller create action is :
def create
#topic= Topic.find(params[:topic_id])
#post = #topic.posts.build(params[:post])
#post.user = current_user
#post.topic_id = #topic.id
if #post.save
flash[:success] = "Yorum oluşturuldu!"
redirect_to topic_path(#topic)
else
render 'static_pages/home'
end
end
This is my error_messages.html.erb:
<% if object.errors.any? %>
<div id="error_explanation">
<div class="alert alert-error">
The form contains <%= pluralize(object.errors.count, "error") %>.
</div>
<ul>
<% object.errors.full_messages.each do |msg| %>
<li>* <%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
If I test the empty post and empty topic. I get this error :
undefined method `each' for nil:NilClass
Extracted source (around line #2):
1:
2: <% #topics.each do |topic|%>
3: <li><%=link_to topic.title, topic_path(topic) %></li>
4:
5: <%= will_paginate #topics %>
My static_pages_controller.rb :
def home
if signed_in?
#topic = current_user.topics.build if signed_in?
end
#topics = Topic.paginate :page => params[:page], :per_page => 20
end
and my home.html.erb:
<% if signed_in? %>
<div class="row">
<%= render 'shared/user_info' %>
<%= render 'shared/topic_form' %>
<ol class="topics-signedin">
<%= render 'shared/topics' %>
</ol>
Why does not errors does not show ?
You are missing #topics in your 'create' action. Yes, it gets set in your 'home', which rendered the form, but on submission, it passed to 'create', which then has to load the variables again, and in your case, there is no #topics set when it goes to render 'static_pages/home'. You need..
...
if #post.save
flash[:success] = "Yorum oluşturuldu!"
redirect_to topic_path(#topic)
else
#topics = Topic.paginate :page => params[:page], :per_page => 20
render 'static_pages/home'
end
You never set #topics, only #topic. So #topics is nil.
And on error you render the static_pages/home, which requires those. You should re-render the new or edit instead.
Related
I am trying to to edit a form through a reveal-modal. So i have multiple posts.
When I click the link 'Edit' it will reveal a div and display a form inside that is repopulated with the information. However, I don't know how to pass the post id into the form it will know which post to edit.
If i try to render the partial form I get this error:
undefined method `model_name' for Post::ActiveRecord_Relation:Class
All my information are on a controller view that is called Dashboard
controllers/dashboards_controller.rb
class DashboardsController < ApplicationController
def index
#profile = Profile.find(current_user)
#profileAll = Profile.all
#post = Post.all
end
def show
end
def edit
#profile =Profile.find(current_user)
#post = #profile.post.find(params[:id])
end
end
controllers/posts_controller.rb
class PostsController < ApplicationController
def create
#profile = Profile.find(current_user)
#post = #profile.post.create(post_params)
redirect_to dashboards_path(current_user)
end
def destroy
#post =Profile.find(params[:profile_id])
#post = profile.post.find(params[:id])
#post.destroy
redirect_to dashboards_path(current_user)
end
def show
#profile =Profile.find(current_user)
#post = #profile.post.find(params[:id])
end
def edit
#profile =Profile.find(current_user)
#post = #profile.post.find(params[:id])
end
def update
#post = profile.post.find(params[:id])
if #post.update(post_params)
redirect_to dashboards_path(current_user)
else
render 'edit'
end
end
private
def post_params
params.require(:post).permit(:title, :content)
end
end
posts/_form2.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 %>
<p>
<%= f.label :title %><br>
<%= f.text_field :title %>
</p>
<p>
<%= f.label :content %><br>
<%= f.text_area :content %>
</p>
<p>
<%= f.submit %>
</p>
<% end %>
routes.rb
Rails.application.routes.draw do
get 'homepages/index'
resources 'dashboards' do
resources 'posts'
end
#get 'users/sign_in'
resources 'profiles' do
resources 'posts'
end
devise_for :users, :controller => {:registrations => "users/registrations"}
devise_scope :user do
root :to => 'devise/sessions#new'
end
end
Dashboards/index.html.erb
<% #post.each do |post| %>
<div class="panel">
<%= #profileAll.find(post.profile_id).name %>
<hr>
<h5><%= post.title %></h5>
<p><%= post.content %></p>
<%# link_to "Edit", edit_dashboard_post_path(current_user,[post.profile, post]) %>
<%= link_to "Edit", {id: #post},'data-reveal-id' => 'edit-post' %>
</div>
<% end %>
<div id="edit-post" class="reveal-modal" data-reveal>
<%= render 'posts/form2' %>
<a class="close-reveal-modal">×</a>
</div>
Well, it simply does not work that way. First, you have in your controller #post = Post.all and within your _form2.html.erb you want to render form for a collection. That should be:
# index.html.erb
<div id="edit-post" class="reveal-modal" data-reveal>
<%= render :partial => 'posts/form2', collection: #posts %>
<a class="close-reveal-modal">×</a>
</div>
#dashboard controller:
def index
#...
#posts = Post.all
end
_form2.html.erb:
Every #post object instance has to be replaced with form2. Read more here: http://api.rubyonrails.org/classes/ActionView/PartialRenderer.html about rendering a collection.
However, consider a case when you have hundreds of posts. Then, for each post, a partial is rendered. That would be very inefficient so instead, consider an asynchronous request which will load only one post the user requested.
I know this is a very basic solution however, I am just not seeing it right now. I am getting a 'Couldn't find Post without an ID' error within CommentsController#create.
I created a 'New Comment' button under the post which should then redirect to the comment form. From there once a user inputs their comments and clicks the 'Create Comment' button the comment should be displayed under the original post. Thank you in advance.
Comments Controller
Class CommentsController < ApplicationController
before_filter :authenticate_user!
def new
#comment = Comment.new
end
def create
#post = Post.find(params[:post_id])
#comment = #post.comments.create(params[:comment].permit(:commenter, :body))
respond_to do |format|
if #comment.save
format.html { redirect_to #post, notice: 'Comment was successfully created.' }
format.json { render json: #comment, status: :created, location: #comment }
else
format.html { render action: "new" }
format.json { render json: #comment.errors, status: :unprocessable_entity }
end
end
end
def destroy
#post = Post.find(params[:post_id])
#comment = #post.comments.find(params[:id])
#comment.destroy
redirect_to post_path(#post)
end
def show
#comment = Comment.new
end
end
Post/Show
<div class="row">
<div class="col-md-offset-4 col-med-8">
<div class="panel panel-default">
<div class="panel-heading center">
<% if #post.image.url %>
<%= image_tag #post.image.url(:medium) %>
<% elsif #post.video.url %>
<%= video_tag #post.video.url(:medium), controls: true, type: "video/mp4" %>
<% end %></br>
<p>
<strong>Likes:</strong>
<%= #post.get_likes.size%>
</p>
<%=link_to image_tag('like.jpg', :border => 0), likes_post_path(#post) %>
<%=link_to image_tag('unlike.jpg', :border => 0), dislikes_post_path(#post) %>
</div>
<div class="panel-body">
<p><%= #post.description %></p>
<% user = #post.user %>
<p><strong><%= link_to(user.name, user_path(user)) if #post.user %></strong></p>
<%= link_to 'New Comment', new_comment_path, class: "btn btn-danger btn-sm active" %></br>
<br><% if #post.user == current_user %>
<%= link_to edit_post_path(#post) do %>
<span class="glyphicon glyphicon-edit"></span>
Edit
<% end %>
<% end %>
<%= link_to 'Back', posts_path %>
</div>
</div>
</div>
Comments / _form
<%= form_for [#post, Comment.new] do |f| %>
<% if #comment.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#comment.errors.count, "error") %> prohibited this comment from being saved:</h2>
<ul>
<% #comment.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :body %><br>
<%= f.text_area :body %>
</div>
<div class="actions">
<%= f.submit class: "btn btn-danger btn-sm" %>
</div>
<% end %>
Routes
resources :comments
resources :posts do
resources :comments
end
Comments / Show
<p id="notice"><%= notice %></p>
<p>
<strong>Post:</strong>
<%= #comment.post_id %>
</p>
<p>
<strong>Body:</strong>
<%= #comment.body %>
</p>
<%= link_to 'Edit', edit_comment_path(#comment) %> |
<%= link_to 'Back', comments_path %>
Rake Routes
post_comments GET /posts/:post_id/comments(.:format) comments#index
POST /posts/:post_id/comments(.:format) comments#create
new_post_comment GET /posts/:post_id/comments/new(.:format) comments#new
edit_post_comment GET /posts/:post_id/comments/:id/edit(.:format) comments#edit
post_comment GET /posts/:post_id/comments/:id(.:format) comments#show
I recommend making the following changes:
Routes:
Remove the first resources :comments. Leave the following:
resources :posts do
resources :comments
end
Posts/Show view:
You should be using new_post_comment_path instead of new_comment_path. Run rake routes to see why.
CommentsController#new:
Define #post in your new action:
def new
#post = Post.find(params[:post_id])
#comment = Comment.new
end
Finally, in Comments/_form:
Change <%= form_for [#post, Comment.new] do |f| %> to <%= form_for [#post, #comment] do |f| %>. Although I believe <%= form_for #comment do |f| %> should work.
I recommend going through the Rails Guides for additional information and explanations.
I believe that in def new of the comments controller, you also need to set #post, not just #comment
I'm having problems with the "First argument in form cannot contain nil or be empty" error that I haven't been able to find an answer for.
Basically, I have Posts, which show up on a User's show page, which should each have the option to comment on them. My routes are as follows:
resources :posts, only: [:create, :destroy] do
resources :comments, only: [:create, :destroy]
end
users/show.html.erb
<ol class="posts">
<%= render #posts %>
</ol>
posts/_post.html.erb
<li>
<span class="content"><%= post.content %></span>
<span class="timestamp">
Posted <%= time_ago_in_words(post.created_at) %> ago.
</span>
<% if current_user?(post.user) %>
<%= link_to "delete", post, method: :delete,
data: { confirm: "You sure?" },
title: post.content %>
<% end %>
<span class="content">
<ul> Comments: <%= post.comments.count %></ul>
<% post.comments.each do |comment| %>
<ul> <%= comment.comment %> </ul>
<% end %>
</span>
<% if post != nil %>
<% form_for [post, #comment] do |f| %>
<%= render 'shared/error_messages', object: f.object %>
<div class="field">
<%= f.text_area :content, placeholder: "Comment..." %>
</div>
<%= f.submit "Post", class: "btn btn-lg btn-primary" %>
<% end %>
<% end %>
</li>
s comments_controller.rb
def create
#post = Post.find(params[:id])
#comment = #post.comments.build(comment_params)
#comment.user = current_user
if #comment.save
flash[:success] = "Posted!"
redirect_to #post
else
render 'static_pages/home'
end
end
def destroy
#comment.destroy
redirect_to root_url
end
Showing C:/app/views/posts/_post.html.erb where line #21 raised: (line 21 is the form_for line)
First argument in form cannot contain nil or be empty
app/views/posts/_post.html.erb:21:in _app_views_posts__post_html_erb___306000501_37434348'
app/views/users/show.html.erb:19:in_app_views_users_show_html_erb__480533737_37130988'
If each post had a show page, I know that I would put #posts on the show action and then make it an instance variable, but since the each post needs a separate comment dialogue box, I can't make it that general. It doesn't go through the posts controller though so I can't make it specific to each post. I'm using acts_as_commentable for the comments. Ideally, I would like to make them generic and put all the form_for comment stuff into a partial, but I'll figure that out later.
I'm tying to perform an edit action on one of my nested models. I keep getting the following error "undefined method `model_name' for NilClass:Class"
I don't know what's going on. Any help?
Routes
resources :users, :except => [ :create, :new ] do
resources :store do
get "inbox", :on => :collection
get "openedmessages", :on => :collection
end
end
Store Actions
def edit
#store = current_user.store.id
end
def create
#store = current_user.store.new(params[:store])
end
def update
#stores = current_user.store.id
if #stores.update_attributes
flash[:success] = "Store has been updated"
render 'edit'
else
render 'edit'
end
end
View for Edit Action in Store
<ul class="storedashboard_header">
<li><%= link_to "Manage Gear", user_store_index_path(current_user) %></li>
<li><%= link_to "Store Appearance", edit_user_store_path(current_user, #store) %></li>
<li><%= link_to "Announcements", '#' %></li>
</ul>
<%= render "users/userdashboard_header" %>
<%= render "store/storemenu" %>
<div style="clear:both"></div>
<% flash.each do |name, msg| %>
<div class="alert alert-success">
<a class="close" data-dismiss="alert">×</a>
<%= msg %>
</div>
<% end %>
<div>
<%= simple_form_for #stores, :html => {:multipart => true, :class => 'form-horizontal'} do |f| %>
</br>
<div style="float: left;">
<%= f.input :storename %>
<%= f.input :storeimage %>
<%= f.input :storelogo %>
<%= f.button :submit, class: 'btn btn-large', style: 'margin-left: 40px;' %>
</div>
<% end %>
</div>
UPDATED
Changed my Controller to the following:
def edit
#store = Store.find(current_user.store.id)
end
def create
#store = current_user.store.new(params[:store])
end
def update
#store = Store.find(current_user.store.id)
if #store.update_attributes(params[:store])
flash[:success] = "Store has been updated"
render 'edit'
else
render 'edit'
end
end
New Error after Update
undefined method `store_path' for #<#:0x007fec93b97238>
FINAL FIX
Needed to fix the view...
<%= simple_form_for [current_user, #store], :html => {:multipart => true, :class => 'form-horizontal'} do |f| %>
if i understand your question properly:
#store needs to be an object for the model Store instead of just the id.
something like:
#store = Store.find(current_user.store.id) will return the object
I get this error:
NoMethodError in Videos#new
Showing /rubyprograms/dreamstill/app/views/videos/new.html.erb where line #1 raised:
undefined method `videos_path' for #<#<Class:0x10398f8d8>:0x10398dbc8>
I have one Video model and a videos controller with a new and create method. My routes.db file has root :to => "videos#new". I have one view new.html.erb with this code:
<%= form_for(#video) do |f| %>
<% if #video.errors.any? %>
<div id="errorExplanation">
<h2><%= pluralize(#video.errors.count, "error") %> prohibited this video from being saved:</h2>
<ul>
<% #video.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :video_url %><br />
<%= f.text_field :video_url %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
And my controller has this:
def new
#video = Video.new
end
def create
#video = Video.new(params[:video])
respond_to do |format|
if #article.save
format.html #{ redirect_to(#video, :notice => 'Article was successfully created.') }
else
format.html { render :action => "new" }
end
end
end
This is all that's in my routes file:
Dreamstill::Application.routes.draw do
root :to => "videos#new"
end
your routes should be
Dreamstill::Application.routes.draw do
root :to => "videos#new"
resources :videos
end