In this Rails app, Users can write Stories and add them to Collections. As they write a Story, users can add it to an existing Collection or create a new one while in the stories/new.html.erb view through a modal.
I have this working for the New action, but the Edit action is broken. It throws an error that says
First argument in form cannot contain nil or be empty on this line
<%= form_for [#user, #collection] do |f| %>
My code looks like this
stories_controller.rb
def new
#story = Story.new
authorize #story
#user = current_user
#collection = Collection.new
end
def edit
#story = Story.friendly.find(params[:id])
end
stories/edit.html.erb loading a _form.html.erb partial
<div class="modal-body">
<%= form_for [#user, #collection] do |f| %>
<div class="form-group">
<%= f.label :name %>
<%= f.text_field :name, class: "form-control" %>
</div>
<div class="form-group">
<%= f.label :description %>
<%= f.text_area :description, class: "form-control collection-desc-input-box", placeholder: "Give it a description (this is optional)" %>
</div>
<div class="form-group">
<%= f.submit class: "btn btn-lakeside" %>
</div>
<% end %>
</div>
routes.rb nested resource
resources :users do
resources :collections
EDIT:
Fixed the problem by putting Collection.new in the edit action. Would be good if someone can explain what's happening. I fixed this by trial and error. Thanks.
def edit
#story = Story.friendly.find(params[:id])
#user = current_user
#collection = Collection.new
end
initialize/set #user and #collection in your edit action, they are nil and so the error. Since they are initialised for new action, it is working.
You can do something like the following for #user and #collection can be initialised in their respective actions accordingly:
before_action :set_user, only: [:new, :edit]
private
def set_user
#user = current_user
end
You missed #user and #collection instance variable in store controller.
Try below code:
#stories_controller.rb
def new
#story = Story.new
authorize #story
#user = current_user
#collection = Collection.new
end
def edit
#story = Story.friendly.find(params[:id])
#user = User.find(params[:id])
#collection = Collection.find(params[:collection_id])
end
Related
I have user model that has many reviews, and each review has many replies.
I want to allow the user to reply under a review.
In a profile page (coming from a profile controller and show action), I want to be able to create replies.
<div class="reply-box d-none" id="reply-box">
<%= form_with(model: Reply, url: new_user_review_reply_path(#user, #review)) do |reply| %>
<%= reply.hidden_field :user_id, value: #user %>
<%= reply.hidden_field :review_id, value: #review %>
<%= reply.text_field :reply_content%>
<div class="comment-box-btns mb-5">
<%= reply.submit "submit", class: 'submit-btn d-inline-block ml-2 float-right'%>
<div class="cancel-btn d-inline-block float-right">cancel</div>
</div>
<% end %>
</div>
Here is the route.rb
resources :users do
resources :reviews do
resources :replies
end
end
Here is the reply controller:
class RepliesController < ApplicationController
def new
#user = User.find(params[:user_id])
#reivew = #user.reviews.find(params[:review_id])
#reply = #reivew.replies.new
end
def create
#user = User.find(params[:user_id])
#reivew = #user.reviews.find(params[:review_id])
#reply = #reivew.replies.create!(reply_params)
respond_to do |format|
format.html {redirect_to(profile_path(param[:user_id]))}
format.js
end
end
private
def reply_params
params.require(:reply).permit(
:reply_content,
:user_id,
:review_id
)
end
end
I don't know how to set up the "form_with". So far it just says
undefined method `reply_content' for #<Class:0x007f8c7396aaa8>
reply_content is the field in reply I want to create using the text_area.
I am very confused. Any help would be greatly appreciated.
As you have already intitilize #reply = #reivew.replies.new in new action so you should use this #reply object with reply form, also i don't think that you need not to explicitly provide value: user_id and value: review_id
<div class="reply-box d-none" id="reply-box">
<%= form_for #reply, url: new_user_review_reply_path(#user, #review) do |reply| %>
<%= reply.hidden_field :user_id %>
<%= reply.hidden_field :review_id %>
<%= reply.text_field :reply_content%>
<div class="comment-box-btns mb-5">
<%= reply.submit "submit", class: 'submit-btn d-inline-block ml-2 float-right'%>
<div class="cancel-btn d-inline-block float-right">cancel</div>
</div>
<% end %>
</div>
I have a provider model which has many comments. I have a current setup working with the form being:
views/comments/_form.html.erb
<%= form_for([#provider, Comment.new] ) do |f| %>
<%= f.text_area :body, cols: 30, rows: 4, class: 'form-control' %>
<%= f.hidden_field :user_id, value: current_user.id, class: "form-control" %>
<div>
</br>
<%= f.submit :post, class: 'btn btn-primary btn-lg' %>
</div>
<% end %>
But I dont think its right from what iv seen around it should be
<%= form_for([#provider, #comment[) do |f| %>
but this method I get the following error
First argument in form cannot contain nil or be empty
I access my comments form from within my provider show.html.erb like this
<%= render 'comments/form', provider: #provider %>
My comments views are just _form.html.erb and _comments.html.erb which lists all the comments for a given provider.
My comments_controller.rb is as follows
class CommentsController < ApplicationController
before_action :set_provider
def new
#comment = Comment.new
end
def create
#provider = set_provider
#comment = #provider.comments.create!(comment_params)
redirect_to #provider
end
def destroy
#provider = set_provider
#comment = Comment.find(params[:id])
#comment.destroy
redirect_to #provider
end
private
def set_provider
#provider = Provider.find(params[:provider_id])
end
def comment_params
params.require(:comment).permit(:body, :user_id)
end
end
If anyone point me in the right direction that would be very much appreciated.
Found the issue.
Because I was showing the Comments in the show action of my provider model I needed this in the Provider
def show
#comment = Comment.new
#provider = find_provider
end
Works perfectly now.
I'm using rails 4.0.8. I added a comment section to a model called 'Things', but I keep getting the same error "param is missing or the value is empty: thing" when I press the submit comment button. It says the error is in the Things#Controller. What am I doing wrong?
UPDATE: I removed the url path from the form, but a new error returns "Couldn't find Thing without an ID". The error is in Comments#Controller.
VIEW FOR THING/SHOW
<div id= "thing">
<h1>
<%= #thing.name %>
</h1>
<br>
<div id= "commentsection">
Comments
<div id= "comments">
<br>
<% #thing.comments.each do |c| %>
<%= c.username %>
<br>
<%= c.text %>
<% end %>
<%= form_for #comment, :url => thing_path do |f| %>
<%= f.label :username %>
<%= f.text_field :username %>
<%= f.label :comment %>
<%= f.text_field :text %>
<%= f.submit "Enter", class: "btn btn-small btn-primary" %>
<% end %>
</div>
</div>
</div>
THINGS CONTROLLER
class ThingsController < ApplicationController
def show
#thing = Thing.find(params[:id])
#thing.comments.build
#comment = Comment.new
end
def index
end
def new
#thing = Thing.new
#things = Thing.all
end
def create
#thing = Thing.new(thing_params)
if #thing.save
redirect_to #thing
else
render 'new'
end
end
private
def thing_params
params.require(:thing).permit(:name, :avatar)
end
end
COMMENTS CONTROLLER (I put asterisks around the line where the error is)
class CommentsController < ApplicationController
def show
#comment = Comment.find(params[:id])
end
def new
#comment = Comment.new
#comments = Comment.all
end
def create
****#thing = Thing.find(params[:thing_id])****
#comment = #thing.comments.create(comment_params)
redirect_to thing_path(#thing)
end
end
private
def comment_params
params.require(:comment).permit(:user, :text, :upvotes, :downvotes, :thing_id)
end
end
ROUTES
Website::Application.routes.draw do
get "comments/new"
get "comments/show"
get "things/new"
root 'home_page#home'
get "all/things/new" => 'things#new'
get "all/allthings"
resources :things
resources :good_comments
get "things/show"
get "things/results"
end
You are posting the #comment form to post '/things' path.
<%= form_for #comment, :url => thing_path do |f| %>
It should just be <%= form_for #comment do %> (Rails is smart enough to plug in the comments_path) or if you feel like being more explicit (even though it's not necessary)
<%= form_for #comment, url: :comments_path do %>
Another note though, if you want that Comment to be tied to that specific Thing then in your models it should be
Class Thing
has_many :comments
end
Class Comment
belongs_to :thing
end
Then make sure in your database comment has a thing_id foreign_key field and then your form for comment should actually look like
<%= form_for #thing, #comment do %>
<% end %>
I am new to Rails and working on creating a generic "facebook" type of app as practice with users and posts associated with each user. However, I'm currently having an issue where I think the form that I am using to create the posts is also being rendered out as a blank post with no post ID where I display all of the posts in a section below. I think that this post is being shown even before it is being saved to the database.
Here is my code in my view:
<div class="newpostcontainer">
<div class="newposttext">
<%= form_for([#user, #user.posts.build]) do |f| %>
<%= f.text_area :post, size: "69x1" %>
</div>
<div class="newpostsubmitbutton">
<%= f.submit %>
</div>
<% end %>
</div>
<% #user.posts.reverse_each do |p| %>
<div class="postedcontainer">
<div class="minipostpic">
<%= image_tag #user.photo.url, width: 32, height: 32 %>
</div>
<div class="nameofposter"><%= #user.name %></div>
<div class="dateofpost"><%= p.created_at%></div>
<div class="postcontent"><%= p.id%></div> <br>
<div class="postcontent"><%= p.post%></div> <br>
<div class="likecommentdelete">
<%= link_to "Delete", [p.user, p], method: :delete %> | Like | Comment
</div>
</div>
<%end%>
</div>
Here is my controller:
def index
#user = User.find(params[:user_id])
#posts = #user.posts.all
end
def create
#user = User.find(params[:user_id])
#post = #user.posts.create!(post_params)
redirect_to user_path(#user)
end
def show
#user = User.find(params[:user_id])
#post = #user.posts.find(params[:id])
redirect_to user_path(#user)
end
def destroy
#user = User.find(params[:user_id])
#post = #user.posts.find(params[:id])
#post.destroy
if #post.destroy
redirect_to user_path(#user)
else
redirect_to users_path
end
end
private
def post_params
params.require(:post).permit!
end
end
And here is my model:
class Post < ActiveRecord::Base
belongs_to :user
has_many :comments
validates_presence_of :post
end
I'm pretty sure the issue has something to do with my form to create the new post because when I remove it or comment it out, the extra blank post with no post ID goes away.
Any thoughts or suggestions?
Thank you!!
I think you need to permit the field values to be posted:
i.e.,
params.require(:post).permit!
should be
params.require(:post).permit(:name, :post)
then only it will POST I think.
Hope it helps :)
This is because of rails 4 strong parameter feature. You need to whitelist your active models parameters. For more details refer to here.
In your case you need to do something like this:
params.require(:post).permit(:post)
where the ":post" inside require is your model and the other one is your permitted field that is your textarea.
Several issues -
Form
<%= form_for([#user, #user.posts.build]) do |f| %>
Why are you building an associative object? #user.posts.build will not persist your data, and will cause all sorts of non-conventional issues I would highly recommending building the posts associative object in your controller's new action before using in the view, so you can do this:
#app/controllers/users_controller.rb
def new
#user = current_user
#user.posts.build
end
<%= form_for #user do |f| %>
Association
You're trying to edit the post attribute with this statement:
<%= f.text_area :post, size: "69x1" %>
This won't work in any circumstance, as :post is an association, not an object. Rails only allows you to change / add attributes to specific objects, which means you'll be better doing something like this:
<%= f.fields_for :posts do |p| %>
<%= p.text_area :title %>
<%= p.text_area :body %>
<% end %>
Strong Params
You're currently permitting all your params? You'll be better doing this:
def post_params
params.require(:user).permit(posts_attributes: [:title, :body])
end
Use Posts Controller
A better way will be to just use the posts_controller, like this:
#app/controllers/posts_controller.rb
def new
#post = Post.new
end
def create
#post = Post.new(post_params)
#post.save
end
#app/views/posts/new.html.erb
<%= form_for #post do |f| %>
<%= f.text_field :title %>
<%= f.text_field :body %>
<% end %>
I have a form that allows the user to Post in the a group Show method. Upon posting, I want to redirect to the same page showing the new post. I'm using the following, but I get the error below. I'm not sure why #group is nil, because I've defined it in the show of my group controller.
No route matches {:id=>nil} missing required keys: [:id]
for
redirect_to group_path(#group)
<%=form_for([#post]) do |f| %>
<%= render 'shared/error_messages', object: f.object %>
<div class = "field">
<%= f.label :event_name %>
<%= f.collection_select(:event_id, #events, :id, :title) %>
</div>
<div class = "field">
<%= f.text_area :comment, placeholder: "New Post..." %>
</div>
<%= f.hidden_field :user_id, value: current_user.id %>
<%=f.submit "Submit", class: "btn btn-large btn-primary" %>
<%end%>
class PostsController < ApplicationController
def create
if #post = Post.create(post_params)
flash[:success] = "Post Created!"
redirect_to group_path(#group)
else
redirect_to group_url
flash[:alert] = "Sorry - Post not created."
end
end
end
def show
#event = #group.events.build
#post = Post.new
#events = #group.events.includes(:posts)
#group = Group.find(params[:id])
end
In your create action you attempt to use the #group instance variable. You haven't defined it in the create action so you'll need to create it there if you want to use it. Since the call to create is in a separate request cycle the instance variables you defined in the show action are not available.
Update:
To get the group if you have an event_id and event belongs_to :group you would do:
event = Event.find(event_id)
#group = event.group
Set #group in create action. You have not assigned any value to #group there which is why you are getting error.
EDIT
As per your comment A Group has_many events so you can find the group as below:
#group = Event.find(params[:event_id]).group