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>
Related
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 table of venues and offers. Each venue can have have many offers.
I would like to be able to add the offers to the venues from the venues edit page. So far I have this (code below) but its giving a "NoMethodError in Venues#edit, undefined method `model_name' for NilClass:Class" error.
venues edit page
(the div id="tabs-3" is a container in an accordion)
<div id="tabs-3">
<%= form_for [#venue, #offer] do |f| %>
<h2 class="venue_show_orange">Offers</h2>
<%= f.fields_for :offers do |offer| %>
<div class="add_offer">
<%= offer.text_field :title %><br>
</div>
<div class="button"><%= submit_tag %></div>
<% end %>
<% end %>
</div>
offers controller
class OffersController < ApplicationController
def new
#offer = Offer.new
end
def create
#offer = #venue.offers.create!(params[:offer])
#offer.venue = #venue
if #offer.save
flash[:notice] = 'Offer added'
redirect_to offers_path
else
render :action => :new
end
end
def edit
#offer = Offer.find(params[:id])
end
def update
#offer = Offer.find(params[:id])
#offer.attributes = params[:offer]
if #offer.save!
flash[:notice] = 'Offer updated successfully'
redirect_to offers_path(#offer)
end
end
end
venues controller
(nothing offer related in here - is this where I'm going wrong?)
class VenuesController < ApplicationController
protect_from_forgery :only => [:update, :delete, :create]
load_and_authorize_resource
def new
#venue = Venue.new
5.times { #venue.venuephotos.build }
end
def create
#venue = Venue.new params[:venue]
if #venue.save
flash[:notice] = 'Venue added'
redirect_to venues_path
else
render :action => :new
end
end
def edit
#venue = Venue.find(params[:id])
5.times { #venue.venuephotos.build }
end
def update
#venue = Venue.find(params[:id])
#venue.attributes = params[:venue]
if #venue.save!
flash[:notice] = 'Venue updated successfully'
redirect_to :back
end
end
end
Any help is much appreciated thanks very much!
edit
venues edit page
<div id="tabs-3">
<%= form_for #venue do |f| %>
<div class="edit_venue_details">
<h2 class="venue_show_orange">Offers</h2>
<%= render :partial => 'offers/offer', :collection => #venue.offers %>
<div class="clearall"></div>
<h2 class="edit_venue_sub_header">Add a new offer</h2>
<%= f.fields_for :offers do |offer| %>
<% if offer.object.new_record? %>
<p class="edit_venue">title: <br>
<%= offer.text_field :title, :class => "edit_venue_input" %></p>
<% end %>
<% end %>
</div>
<button class="submit_button" type="submit"> Save changes</button>
<% end %>
</div>
whats being displayed
however if I add a new offer, that will display correctly:
Some remarks:
1) Replace:
<%= form_for [#venue, #offer] do |f| %>
with:
<%= form_for #venue do |f| %>
Because offers data will be updated through the related venue, only one controller action will handle the form.
2) If you want to add some unexisting offers in this form, you shoud instantiate them the way you did with venuephotos
3) Show your Venue model. You should have at least:
accepts_nested_attributes_for :offers
Fixed with:
<%= f.fields_for :offers, #venue.offers.build do |offer| %>
My app has a user model and a post model, where user has_many posts and posts belong_to users. Posts are displayed on a user's profile page. I'd like for any user to be able to post on his own, or any other user's profile page. However, the problem I'm having is that while I know who is posting (current_user), I don't know whose profile current_user is on. I need to know this in order to assign the new post to that user's posts. How do I extract user id information from the profile currently being viewed, so I know where to assign the new post?
My micropost controller looks like:
class MicropostsController < ApplicationController
before_filter :authenticate_user!
def create
#user_of_page = User.find_by_name(params[:id])
#micropost = #user_of_page.microposts.build(params[:micropost])
if #micropost.save
flash[:success] = "Micropost created!"
redirect_to :back
else
redirect_to about_path
end
end
def destroy
end
end
But I'm getting a NoMethodError: undefined method `microposts' for nil:NilClass. I assume this is because I'm making some mistake with the creation of the user_of_page variable, but I don't know what that is!
SOLUTION
Thanks Sam. I took your advice and ended up doing it like this:
I added a column to my Micropost table called belongs_to_id.
I then passed the id of the user whose profile is being shown from the user show view to the micropost controller using a hidden field in the micropost form, like so:
<%= form_for #micropost do |f| %>
<%= render 'shared/error_messages', :object => f.object %>
<div class="field">
<%= f.label :content, "Why that mood?" %>
<%= f.text_area :content %>
</div>
<div class="field">
<%= f.hidden_field :author, :value => current_user.name %>
<%= f.hidden_field :belongs_to_id, :value => #user.id %>
<%= f.hidden_field :agree, :value => "0" %>
<%= f.hidden_field :disagree, :value => "0" %>
<%= f.hidden_field :amused, :value => "0" %>
</div>
<div class="actions">
<%= f.submit "Submit" %>
</div>
<% end %>
I then used this id value to search for the user to assign the post to, in the micropost controller, like so:
class MicropostsController < ApplicationController
before_filter :authenticate_user!
def create
#user_of_page = User.find(params[:micropost][:belongs_to_id])
#micropost = #user_of_page.microposts.build(params[:micropost])
if #micropost.save
flash[:success] = "Micropost created!"
redirect_to :back
else
redirect_to about_path
end
end
def destroy
end
end
Magic! Thanks again, you helped me to see it in the right way.
I would do it like this:
class profiles_controller < AC
...
def show
#profile = User.find(params[:id]).profile || current_user.profile
#post = Post.new
end
..
end
/profiles/show.html.erb
...
Name: <%= #profile.full_name %>
...
<%= form_for #post do |f| %>
<%= hidden_field_tag #profile.user %>
...
<% end %>
class microposts_controller < AC
def create
profile_user = User.find(params[:user_id]) # Owner of the profile current_user is on
..
end
end
Not tested. Hope this helps.
I have a status update, and comment db table.
A user has many status updates, and a status update has many comments. Similar to facebook, When a users friend goes to the users feed page (show page), they should be able to comment on the users status updates.
I'm having issues saving a users friends comment.. my code is below.. I think it has something to do with the Comments Controller, Create method, "#comment = #statusupdate.comments.build(params[:comment])"
any guidance is much appreciated! thanks!
class UsersController < ApplicationController
def show
#user = User.find(params[:id])
#statusupdates = #user.statusupdates.paginate(:page => params[:page], :per_page => 25)
#statusupdate = Statusupdate.new
#comment = Comment.new
end
end
show.html.erb
<% form_for #statusupdate do |f| %>
<%= f.error_messages %>
<div class="field">
<%= f.text_field :content %>
</div>
<% #statusupdates.each do |s| %>
<%= s.content %><br />
<% form_for #comment do |f| %>
<%= f.error_messages %>
<div class="field">
<%= f.text_field :comment %>
</div>
<div class="field">
<%= f.hidden_field :user_id, :value => current_user.id %>
</div>
<div class="actions">
<%= f.submit "Submit" %>
</div>
<br><br>
<% end %>
<% end %>
class CommentsController < ApplicationController
def create
#comment = #statusupdate.comments.build(params[:comment])
if #comment.save
flash[:success] = "Comment created!"
redirect_to root_path
else
#feed_items = []
render 'pages/home'
end
end
end
Check the html of the form to make sure its right. Also see what parameters are getting sent to the create action.
The main thing I see is that the forms for the status update and the comments are nested, and both use the block parameter f. This could cause things to get very strange (especially since the scoping of block parameters differs between ruby 1.8 and 1.9). It also seems like you don't actually want the forms nested. You should also probably fix the indentation in your html.
show.html.erb- I changed the top line of the status update comment form to:
<% form_for (s, s.comments.build) do |f| %>
...
class CommentsController < ApplicationController
def create
#statusupdate = statusupdate.find(params[:statusupdate_id])
#comment = #statusupdate.comments.create(params[:comment])
...
I don't exactly know what's going on here but it worked for me~ hope it helps someone out~