Ruby on Rails: Form routes to a different URL - ruby-on-rails

I have a form that saves data, but it gets routed to the wrong URL.
If my form is in
localhost:3000/users/1/styles/1
And when I submit the form, I get redirected to this:
localhost:3000/styles/1
and then I get an error:
Couldn't find User without an ID
views/comments/_form.html.erb
<%= form_for [#commentable, #comment] do |f| %>
<%= f.text_area :content, rows: 3 %>
<%= f.submit %>
<% end %>
styles_controller.rb
def show
#user = User.find(params[:user_id])
#style = #user.styles.find(params[:id])
#commentable = #style
#comments = #commentable.comments
#comment = Comment.new
end
comments_controller.rb
before_filter :get_commentable
def new
#comment = #commentable.comments.new
end
def create
#comment = #commentable.comments.new(params[:comment])
#comment.user = current_user
if #comment.save
redirect_to #commentable, notice: "Comment created."
else
render :new
end
end
private
def get_commentable
#commentable = params[:commentable].classify.constantize.find(commentable_id)
end
def commentable_id
params[(params[:commentable].singularize + "_id").to_sym]
end
routes.rb
resources :styles do
resources :comments, :defaults => { :commentable => 'style' }
end
Please let me know if there's other information that is needed. Why am I getting rerouted to a different url? My comment does save into my database.
Thank you

If you want to go back to localhost:3000/users/1/styles/1 after creating comment, you should change
if #comment.save
redirect_to #commentable, notice: "Comment created."
else
to
if #comment.save
redirect_to [User.find(params[:user_id]), #commentable], notice: "Comment created."
else
Edit: Should use User that owns the style not current user

Related

Creating a nested resource in Rails 5

I am trying to create a nested resource so that products can have notes associated with them. I have set up the associations within the model etc, but when I try to use the form to create a new note, I get the following error:
NoMethodError in Notes#create
Showing /Users/myusername/myapp/app/views/notes/_form.html.erb where line #2 raised:
undefined method `notes_path' for #<#<Class:0x00007fb3630b1ad0>:0x00007fb361eab868>
This is the line it is referring to:
<%= simple_form_for [#product, #note] do |f| %>
This are the new & create actions in the notes controller:
def new
#product = Product.find(params[:product_id])
#note = #product.notes.build
end
def create
#note = Note.new(product: #product)
respond_to do |format|
if #note.save
format.html { redirect_to product_notes, notice: 'Note was successfully created.' }
else
flash.now[:error] = "It doesnt work"
render 'new'
end
end
end
and the form partial:
<%= simple_form_for [#product, #note] do |f| %>
<%= f.error_notification %>
<%= f.error_notification message: f.object.errors[:base].to_sentence if f.object.errors[:base].present? %>
<div class="form-inputs">
<%= f.input :content %>
<%= f.input :author %>
<%= f.check_box :visible %>
</div>
<div class="form-actions">
<%= f.button :submit %>
</div>
<% end %>
I am going round in circles with making changes, and cannot seem to find any documentation on nested resources that isn't deprecated. Can anybody assist, please?
Edited to add:
I changed my controller action to something based on PGill's answer and can now get the page to load without an action controller error. However, it now re-renders the new note form, with errors saying that the form fields cannot be blank. They were not blank when I submitted them - what's happening to cause this?
Updated controller action:
def create
#product = Product.find(params[:product_id])
#note = #product.notes.new
respond_to do |format|
if #note.save
format.html { redirect_to product_notes_path(#product), notice: 'Note was successfully created.' }
else
format.html { render :new, notice: 'Note failed to be created.' }
end
end
end
When I was previously getting errors, it had this as the request parameters, so they are getting passed?
Parameters:
{"utf8"=>"✓",
"authenticity_token"=>"lotsofletters",
"note"=>{"content"=>"test", "author"=>"test", "visible"=>"0"},
"commit"=>"Create Note",
"product_id"=>"1"}
Referring to your edit; of course you should get empty fields errors because you are creating a new object #note without providing any attributes for it:
#note = #product.notes.new
it should be like
#note = #product.notes.build(params[:note])
also take care to provide a sanitizer for note in notes controller :
private
def note_params
params.require(:note).permit(:content, :author, :visible, :product_id)
end
so your code in create will look like:
def create
#product = Product.find(params[:product_id])
#note = #product.notes.build(note_params)
respond_to do |format|
if #note.save
format.html { redirect_to product_notes_path(#product), notice: 'Note was successfully created.' }
else
flash.now[:error] = "It doesnt work"
render 'new'
end
end
end
private
def note_params
params.require(:note).permit(:content, :author, :visible, :product_id)
end
#product is nil in create
Your form is failing validations and rendering new
update the create action to
def create
#product = Product.find(params[:product_id])
#note = #product.notes.new
respond_to do |format|
if #note.save
format.html { redirect_to product_notes_path(#product), notice: 'Note was successfully created.' }
else
flash.now[:error] = "It doesnt work"
render 'new'
end
end
end
redirect_to should be product_notes_path(#product) notes#index

Rails 4 - "Create" action in controller when it's a nested route

I have a User model that has_many Photos (another model). In the routes.rb file it's photos is a nested resource of user. So, I have a form_for that uploads to the controller #create action. I'm having trouble saving the photo into the database under the user. How can I do this? It says it saves correctly, because it redirects, but then it doesn't show that it has a photo (I also used the console to check not just my view). What am I doing wrong?
class PhotosController < ApplicationController
def new
#photo = Photo.new(:user_id => params[:user_id])
end
def create
byebug
#photo = Photo.new(params[:user_id])
if #photo.save
flash[:notice] = "Successfully added photo."
redirect_to new_user_photo_path
else
render :action => 'new'
end
end
end
EDIT----------
Adding in the form_for that gets us to the #create action. Hope this helps :) I've been reading more about this, and I'm still not sure what to do to fix.
<%= form_for #photo, :url => user_photos_path(current_user.id, #photo), :html => {:multipart => true} do |f| %>
<div class="form-group">
<%= f.file_field :image %>
</div>
<%= f.submit 'Upload', class: 'btn btn-success' %>
or
<%= link_to 'Cancel', users_path %>
<% end %>
class PhotosController < ApplicationController
def new
#user = User.find(params[:user_id])
#photo = Photo.new(:user_id => params[:user_id])
#photos = #user.photos
end
def create
#photo = User.find(params[:user_id]).photos.new(photo_params)
if #photo.save
flash[:notice] = "Successfully added photo."
redirect_to new_user_photo_path
else
render :action => 'new'
end
end
# GET /photos
def index
redirect_to new_user_photo_path
end
# GET /photos/1
def show
#photo = Photo.find(params[:id])
end
def edit
#photos = Photo.all
#photo = Photo.new
end
def destroy
#photo = User.find(params[:user_id]).photos.find(params[:id])
#photo.destroy
flash[:notice] = "Successfully deleted photo"
redirect_to new_user_photo_path
end
def photo_params
params.require(:photo).permit!
end
end

Nested attributes undefined user_comments_path error

I'm trying to follow Ryan Bates polymorphic models tutorial (Rails 3), to implement comments in my photo model. I'm having trouble when trying to create a new comment for photos since I'm in Rails 4 and I have to deal with :comment strong parameters.
Error: undefined method `user_comments_path' for #<#:0x00000107c8a200>
I have nested resources
#Nesting Resources
resources :users do
resources :photos do
resources :comments
resources :tags
end
end
So the route should be /users/friendly-id/photos/friendly-id/comments, but it's getting badly constructed, I have <%= form_for [#user, #commentable, #comment] do |f| %> in my form.
Photo Controller
#create
def show
#photo = Photo.friendly.find(params[:id])
#user = #photo.user
#tag = Tag.new
#tag.photo_id = #photo.id
#category = Category.all
#commentable = #photo
#comments = #commentable.comments
#comment = Comment.new
#zone = Zone.all
respond_to do |format|
format.html #show.html.erb
format.json {render json: #photo}
end
end
Form
<%= form_for [#user, #commentable, #comment] do |f| %>
<% if #comment.errors.any? %>
<div class="error_messages">
<h2>Please correct the following errors.</h2>
<ul>
<% #comment.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
Comments controller
class CommentsController < ApplicationController
before_filter :load_commentable
def index
#comments = #commentable.comments
end
def new
#comment = #commentable.comments.new
end
def create
#comment = #commentable.comments.new(comment_params)
if #comment.save
redirect_to #commentable, notice: "Comment created."
else
render :new
end
end
private
def load_commentable
resource, id = request.path.split('/')[1, 2]
#commentable = resource.singularize.classify.constantize.find(id)
end
def comment_params
require(:comment).permit(:photo_id, :user_id, :content)
end
###Error 2: When I put friendly.id instead of only id in `load_commentable` method I get a Forbidden Attribute error.
end
Please someone help! Thank you

Rendering a form partial within a different controller in rails

I have an Items model that has_many Photos (which belongs_to Items), both namespaced under Admin.
Uploading via the form works as expected via the Photo's new or edit action(, but not when rendered from the Item show page, I get an "undefined method `model_name' for NilClass:Class" error.When I create a new photo record I pass in the item_id and I'm not sure what to pass into the form on the items page.
PhotosController;
class Admin::PhotosController < Admin::BaseController
def new
#photo = Photo.new(:item_id => params[:item_id])
end
def create
#photo = Photo.new(params[:photo])
if #photo.save
flash[:notice] = "Successfully created photo."
redirect_to [:admin,#photo.item]
else
render :action => 'new'
end
end
def edit
#photo = Photo.find(params[:id])
end
def update
#photo = Photo.find(params[:id])
if #photo.update_attributes(params[:photo])
flash[:notice] = "Successfully updated photo."
redirect_to [:admin,#photo.item]
else
render :action => 'edit'
end
end
def destroy
#photo = Photo.find(params[:id])
#photo.destroy
flash[:notice] = "Successfully destroyed photo."
redirect_to [:admin,#photo.item]
end
end
photos/_form.html.haml;
= form_for [:admin,#photo], :html => {:multipart => true,id: 'upload'} do |f|
= f.hidden_field :item_id
%p
= f.label :name
%br/
= f.text_field :name
%p
= file_field_tag :image, multiple: true, name:'photo[image]',id: 'photo_image'
%p= f.submit
items/show.html.haml;
= render 'admin/photos/form'
doh! figured it out
the render call should be;
= render 'admin/photos/form', :photo => #item.photos.build
and the form
= form_for [:admin,photo]
or you can create a #photo variable in your items_controller#show like
#photo = #item.photos.build
and in your partial
form_for[:admin,#photo]
i think this would be better, because all of your variables get assigned in the controller and not one in the controller and the other in the view.

User and associated Post

I created an twiiter like app, where friends can post, but i want a include the name of the person who created the post in the list showing all the post.
here is my code
class PostsController < ApplicationController
def index
#posts = Post.all(:order => "created_at DESC")
respond_to do |format|
format.html
end
end
def create
#post = Post.create(:message => params[:message])
respond_to do |format|
if #post.save
format.html { redirect_to posts_path }
format.js
else
flash[:notice] = "Message failed to save."
format.html { redirect_to posts_path }
end
end
end
end
`
Assuming, of course, that the 'user has many posts' association is set, and the user model has a 'username' field, you can do this in your view :
<% #posts.each do |post| %>
<%= post.user.username %>
<% end %>

Resources