Posting data on haml form and put routing error - ruby-on-rails

I have a show form and want to add a form to edit this so that a user can input a ticket id. I had initially amended this in the controller as an edit action but have since changed this to update. When i click on the submit button i get an error that says "No route matches [PUT]" and i feel a bit as though i may have missed a step somewhere.
edit.html.haml
= form_for [:admin, #diagnostic], url: edit_admin_diagnostic_path do |f|
.field
= label_tag :ticket_id
= text_field_tag "ticket_id"
= submit_tag "Submit", method: :put, data: { confirm: "Are you sure?" }
.field
= link_to 'show', admin_diagnostic_path
diagnostics_controller
class Admin::DiagnosticsController < Admin::BaseController
before_filter :diagnostic, only: [:show, :delete, :edit, :update]
def index
#diagnostics = DiagnosticInfo.all.order_by(:created_at.desc).page(params[:page]).per(50)
end
def show
respond_to do |format|
format.html
format.json { render json: #diagnostic }
end
end
def update
#diagnostic = DiagnosticInfo.find(params[:id])
if allowed.empty?
render action: "edit", error: 'Un-allowed attribute update request!'
elsif #diagnostic.update_attributes(allowed)
redirect_to admin_lessons_url, notice: 'Lesson was successfully updated.'
else
render action: "edit"
end
end
end
def destroy
diagnostic.destroy
redirect_to admin_diagnostics_path
end
relevant part of routes.rb
resources :diagnostics, only: [:index, :show, :destroy, :edit, :update] do
put 'ticket_id', on: :collection
end

As far as I know form argument should be:
= form_for [:admin, #diagnostic], url: admin_diagnostic_path(#diagnostic) do |f|
not edit_admin_diagnostic_path
edit_admin_diagnostic_path is going to get the edit page for admin_diagnostic while you are looking for put/patch
In your case you are trying to send put request to .../edit url which obviously doesn't exist hence this error.

Related

Rails 6 - 'missing required keys: [:post_id]' when trying to render a 'comment' form directly on my posts#index view

I've been trying to build a facebook/blog type app where comments show directly under new posts, and you can also POST a new comment by rendering a form directly under the corresponding Post. As you'll learn in the rest of my post, I'm fairly new to Rails so any resources that directly help me understand the issue I'm having (even if it's just pointing me to the right parts of the Rails docs) would be super helpful.
As of right now, my homepage renders the post#index action, as well as a a post form so that you can create new posts directly on the index page. All of this works fine until I try to render my comment form. As a note, I'm only focusing on creating a new comment before implementing editing and deleting (not that that should affect anything I wouldn't think).
Unfortunately I keep getting this error -
Moreover, when I split each of these pages into a more traditional, link_to XXXX_path style where every form and action is on its own url page, everything works fine. I think there might be something fundamental that I'm just not understanding. So, before showing my code I'll just give a quick explanation of my understanding of how I expect things to work in my app
On the index.html.erb view:
Render the index page
Show each individual post and any corresponding info I want to display with my each method.
pass the specific instance of Post using <%= render 'comment_form', :post => post %>. This should also give me access to all of the params of said instance of post in my _comment_form.html.erb partial.
On the _comment_form.html.erb partial:
add model: [post, #comment] (as my comment controller is nested in post) so that Rails knows to build a new comment with the associated post instance that was pushed through my index view.
At the end of the day, if I had to guess, my issue is with my controllers - I feel like I've put the correct code in the methods/actions, but my hunch is that there's something conflicting between the #post instance variable and the post instance being iterated over in my each method. I'm really not sure what the problem is and any help would be much appreciated. I hope I didn't over (or under) explain my problem. Thanks for the help in advance!
views/posts/index.html.erb
<p id="notice"><%= notice %></p>
<nav>
</nav>
<h1>Posts</h1>
<table>
<thead>
<tr>
<th>User</th>
<th>Body</th>
<th colspan="3"></th>
</tr>
</thead>
<%= render 'form' %>
<tbody>
<% #posts.each do |post| %>
<tr>
<td><%= link_to post.user.email, user_path(post.user_id) %></td>
<td><%= post.body %></td>
<td><%= link_to 'Show', post %></td>
<td><%= link_to 'Edit', edit_post_path(post) %></td>
<td><%= link_to 'Destroy', post, method: :delete, data: { confirm: 'Are you sure?' } %></td>
<td>
</tr>
<tr>
<%= render 'comment_form', :post => post %>
</tr>
<% end %>
</tbody>
</table>
<br>
<%= link_to 'New Post', new_post_path %>
views/posts/_comment_form.html.erb
<% if user_signed_in? %>
<%= form_with(model: [post, #comment], url: post_comments_path, method: "post", local: true) do |form| %>
<div class="field">
<%= form.label :body %>
<%= form.text_area :body %>
</div>
<div class="actions">
<%= form.submit %>
</div>
<% end %>
<% else %>
Please sign in to comment on the post!
<% end %>
posts_controller.rb
class PostsController < ApplicationController
before_action :set_post, only: [:show, :edit, :update, :destroy]
#before_action :authenticate_user!
# GET /posts
# GET /posts.json
def index
#posts = Post.all.order("created_at DESC")
#post = post_exists?
end
# GET /posts/1
# GET /posts/1.json
def show
end
# GET /posts/new
def new
#post = current_user.posts.build
end
# GET /posts/1/edit
def edit
end
# POST /posts
# POST /posts.json
def create
#post = current_user.posts.build(post_params)
respond_to do |format|
if #post.save
format.html { redirect_to index, 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 #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
# 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
# Only allow a list of trusted parameters through.
def post_params
params.require(:post).permit(:body)
end
def post_exists?
current_user.posts.build if current_user != nil
end
end
comments_controller.rb
class CommentsController < ApplicationController
def new
#post = Post.find(params[:post_id])
#comment = #post.comments.build
end
def create
#post = Post.find(params[:post_id])
#comment = #post.comments.build(comments_params)
#comment.user_id = current_user.id
respond_to do |format|
if #comment.save
format.html { redirect_to posts_path, notice: 'Post was successfully created.' }
format.json { render :show, status: :created, location: #comment }
else
format.html { render :new }
format.json { render json: #comment.errors, status: :unprocessable_entity }
end
end
end
def destroy
end
private
def comments_params
params.require(:comment).permit(:body)
end
end
routes.rb
devise_for :users, controllers: {
sessions: 'users/sessions'
}
devise_scope :user do
get '/users/sign_out' => 'devise/sessions#destroy'
end
resources :posts do
resources :comments, only: [:new, :create, :destroy]
end
resources :users
root to: 'posts#index'
Models
>user.rb
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :validatable
has_many :posts, dependent: :destroy
has_many :comments, dependent: :destroy
>post.rb
belongs_to :user
has_many :comments, dependent: :destroy
>comment.rb
belongs_to :user
belongs_to :post
The error is saying that it is missing the post_id on line 2 in your comment_form.
You got:
<%= form_with(model: [post, #comment], url: post_comments_path, method: "post", local: true) do |form| %>
The url is set to post_comments_path but it doesn't knows which post so you need to pass the post to it as an argument like so:
<%= form_with(model: [post, #comment], url: post_comments_path(post), method: "post", local: true) do |form| %>
Although this will probably solve the current error, you will hit another error since you also got #comment in the comment_form and in your posts#index you don't declare #comment. You also can't declare #comment because it is depending on the post. You could try to solve that with:
<%= form_with(model: [post, post.comments.new], url: post_comments_path, method: "post", local: true) do |form| %>

change routes of update rails

I have a doubt in changing a route value.
I have this situation:
routes.rb
patch 'supplies/update'
get 'supplies/edit'
get 'supplies/index'
views/supplies/edit.html.erb
<%= form_for #supply , :url => supplies_update_path(id: #supply) do |f| %>
....
i would use in the edit.html.erb file the following code:
<%= form_for #supply do |f| %>
what i have to change in the route to obtain the correct supply_path for this form_for?
thank you.
EDIT:
class SuppliesController < ApplicationController
before_action :set_supply, only: [:show, :edit, :update, :destroy]
load_and_authorize_resource
# GET /supplies/index
def index
#supplies = Supply.includes(:product).all
end
def edit
end
# PATCH/PUT /supplies/1
def update
respond_to do |format|
if #supply.update(supply_params)
format.html { redirect_to supplies_index_path, notice: 'Quantità Aggiornata.' }
format.json { render :show, status: :ok, location: #user }
else
format.html { render :edit }
format.json { render json: #supply.errors, status: :unprocessable_entity }
end
end
end
private
def set_supply
#supply = Supply.includes(:product).find(params[:id])
rescue ActiveRecord::RecordNotFound
render :template => 'public/404.html'
end
def supply_params
params.require(:supply).permit(:quantity)
end
end
You can simply use <%= form_for #supply do |f| %> for edit.html.erb file. Reason is: When you instantiate #supply in edit method in SuppliesController, Rails will automatically post the form to update method, you do not need to tell it explicitly. Same way, in new.html.erb, you will also use the same: <%= form_for #supply do |f| %>, but now in your new method, you will do #supply = Supply.new, Rails will post this form to create method.
You do need to define routes, but as far as correct path is concerned, Rails will take care of it as long as you provide correct #supply variable in form_for.
Edit:
In your routes file:
resources :supplies

undefined method `albums_path'

I dont understand why this is happening but I am getting this error.
undefined method albums_path and it says that it is on the first line in this code:
<%= form_for #album, :html => { :class => 'form-horizontal', multipart: true } do |f| %>
<div class="control-group">
<%= f.label :name, :class => 'control-label' %>
<div class="controls">
but I dont see why. here is my controller:
class AlbumsController < ApplicationController
before_action :set_album, only: [:show, :edit, :update, :destroy]
respond_to :html
def index
#user = User.find_by_id(params[:id])
#albums = Album.all.where(:user_id => #user)
end
def show
redirect_to user_albums_url
end
def new
#album = Album.new
end
def edit
end
def create
#album = current_user.albums.new(album_params)
respond_to do |format|
if #album.save
if params[:images]
params[:images].each { |image|
#album.pictures.create(image: image)
}
end
format.html { redirect_to #album, notice: 'Gallery was successfully created.' }
format.json { render json: #album, status: :created, location: #album }
else
format.html { render action: "new" }
format.json { render json: #album.errors, status: :unprocessable_entity }
end
end
end
def update
#album.update(album_params)
redirect_to user_albums_url
end
def destroy
#album.destroy
redirect_to user_albums_url
end
private
def set_album
#album = Album.find(params[:id])
end
def album_params
params.require(:album).permit(:name, :description, :images)
end
end
and my routes are as follows:
resources :users do
resources :albums do
resources :pictures do
resources :comments
end
end
end
Ive looked everywhere for my code even mentioning "albums_path" but it doesnt say it anywhere. Is there anything that you guys can think of being the problem? I've tried fixing the forms but it doesnt seem to work. another thing that you might want to see is the link to new action. here it is:
<%= link_to 'New Album', new_user_album_path(:user_id => current_user.id), :class => 'btn btn-mini' %>
I don't know if this helps at all but I'm using the paperclip gem to create albums.
Your albums resource is nested within users resource. Therefore you should set user in your new action (or, better, in before_filter):
before_filter :set_user
# ...
def set_user
#user = User.find(params[:user_id])
end
and add user reference to your form:
form_for [#user, #album] do |f|
BTW, instead of #albums = Album.all.where(:user_id => #user), you can have (it's much more idiomatic in Rails): #albums = #user.albums.

Rails 4.0 ActiveRecord::RecordNotFound

I am trying to learn Rails and am making my first app and am running into this error:
ActiveRecord::RecordNotFound in PartsController#show
Couldn't find Part with id=new_ic
with the highlighted source:
def set_part
#part = Part.find(params[:id])
end
I am brand new to rails and i can't figure out what is wrong and I can't find any help online either. The app is a part management system for electronic components. The form gets filled out and the data is saved to the database for future reference/updating. Could someone please help?
Source code time:
parts/_ic_form.html.erb
<h1>Add An IC</h1>
<%= simple_form_for #parts do |f| %>
<%= f.input :component_type, :as => :hidden, :input_html => { :value => "IC"} %>
<%= f.input :ic_model, label: 'IC Model' %>
<%= f.input :ic_manufacturer, label: 'IC Manufacturer' %>
<%= f.input :ic_pinCount, label: 'IC Pin-Count' %>
<%= f.input :ic_mountType, collection: ["Through Hole", "Surface Mount"], label: 'IC Mount Type' %>
<%= f.input :ic_package, label: 'IC Package' %>
<%= f.input :ic_quantityOnHand, label: 'Quantity On Hand' %>
<%= f.input :ic_quantityOnOrder, label: 'Quantity On Order' %>
<%= f.button :submit %>
<% end %>
parts/new_ic.html.erb
<%= render 'ic_form' %>
parts/new.html.erb
<h1>New part</h1>
<%= link_to 'IC', 'new_ic' %>
<%= link_to 'Back', parts_path %>
parts_controller.rb
class PartsController < ApplicationController
before_action :set_part, only: [:show, :edit, :update, :destroy]
before_filter :initialize_parts
def initialize_parts
#parts = Part.new
end
# GET /parts
# GET /parts.json
def index
#parts = Part.all
end
# GET /parts/1
# GET /parts/1.json
def show
end
# GET /parts/new
def new
#part = Part.new
end
# GET /parts/1/edit
def edit
end
# POST /parts
# POST /parts.json
def create
#part = Part.new(part_params)
respond_to do |format|
if #part.save
format.html { redirect_to #part, notice: 'Part was successfully created.' }
format.json { render action: 'show', status: :created, location: #part }
else
format.html { render action: 'new' }
format.json { render json: #part.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /parts/1
# PATCH/PUT /parts/1.json
def update
respond_to do |format|
if #part.update(part_params)
format.html { redirect_to #part, notice: 'Part was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: 'edit' }
format.json { render json: #part.errors, status: :unprocessable_entity }
end
end
end
# DELETE /parts/1
# DELETE /parts/1.json
def destroy
#part.destroy
respond_to do |format|
format.html { redirect_to parts_url }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_part
#part = Part.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def part_params
params[:part]
end
end
routes.rb Pretty sure i screwed this one up too
Pms::Application.routes.draw do
resources :parts
resources :parts
root to: "parts#new_ic"
end
rake routes Output:
Prefix Verb URI Pattern Controller#Action
parts GET /parts(.:format) parts#index
POST /parts(.:format) parts#create
new_part GET /parts/new(.:format) parts#new
edit_part GET /parts/:id/edit(.:format) parts#edit
part GET /parts/:id(.:format) parts#show
PATCH /parts/:id(.:format) parts#update
PUT /parts/:id(.:format) parts#update
DELETE /parts/:id(.:format) parts#destroy
GET /parts(.:format) parts#index
POST /parts(.:format) parts#create
GET /parts/new(.:format) parts#new
GET /parts/:id/edit(.:format) parts#edit
GET /parts/:id(.:format) parts#show
PATCH /parts/:id(.:format) parts#update
PUT /parts/:id(.:format) parts#update
DELETE /parts/:id(.:format) parts#destroy
root GET / parts#new_ic
One problem is in this line:
<%= link_to 'IC', 'new_ic' %>
link_to should look like this:
link_to "Profile", profile_path(#profile)
#Profile is the name
#profile_path(#profile) is the link
Try this instead:
#parts/new.html.erb
<%= link_to 'IC', root_path %>
in your routes, root GET / parts#new_ic is linking to your new_ic action. I'd disagree with the way you access it (via root) - but it will work if you want to access the new_ic action. Why is this your root route, though?

No route matches {:action =>"destroy"

I'm getting the following error when trying to destroy a user's vote on a "contribution":
No route matches {:action=>"destroy", :controller=>"contribution_votes",
:id=>#<ContributionVote contribution_id: 8245, user_id: 40>}
But have no idea why. Here is the button sending the request
<%= button_to "undo voteup!",
contribution.contribution_votes.find_by_user_id(current_user),
:method => :delete, :class => 'contribution_vote undo' %>
Here's the "destroy" action in the controller:
def destroy
#vote = current_user.contribution_votes.find(params[:id])
#vote.destroy
#contribution = Contribution.find_by_id(#vote.contribution_id)
#contribution_decrement = #contribution.decrement(:votes)
if #vote.destroy and #contribution_decrement.save
respond_to do |format|
format.html {redirect_to :back}
format.js
end
else
redirect_to :back
end
end
(some redundancy here I know, but it's to be filled in at a later date)
And here's the setup in routes.rb
resources :contribution_votes, :only => [:create, :destroy]
Can anyone help? I suspect the answer's obvious but I can't find it anywhere on SO.
Change your code in view to (I think it will help):
<%= button_to "undo voteup!",
contribution_votes_path(current_user.id),
:method => :delete, :class => 'contribution_vote undo' %>
.. by the way: type rake routes in your console and verify that you use right route path (I can mistake).

Resources