Wicked gem cannot find wedding ID in update action - ruby-on-rails

I'm trying to implement the 'Wicked' gem for wizards and cannot figure out this error for the life of me. Already referenced Ryan bates railscast #346 and the step by step tutorial by schneems.
I have 2 controllers: Weddings and Wedding_steps. The user initially creates a Wedding and after the create action is redirected to the Wedding_steps controller (which uses Wicked) to update the wedding model with additional info.
The wedding_id is successfully detected in the first step weddingdetails, but after submitting that step, I get the following error:
ERROR
ActiveRecord::RecordNotFound in WeddingStepsController#update
Couldn't find Wedding without an ID:
app/controllers/wedding_steps_controller.rb:11:in `update'
Parameters:
{"utf8"=>"✓",
"_method"=>"put",
"authenticity_token"=>"JMd+8gf4rVqOSNMSFrKcD3WxK+X3zvYliSMWqTg0SkE=",
"wedding"=>{"bridename"=>"",
"groomname"=>"",
"weddingdate"=>"",
"weddingcity"=>"",
"weddingstate"=>"",
"url"=>""},
"commit"=>"Next",
"id"=>"wedding_id=11"}
It is supposed to continue to the next step /wedding_steps/eventdetails?wedding_id=11 but instead gives the error and goes to /wedding_steps/wedding_id=11
Also of note is that without the Update action in place, the information successfully saves and redirects to the Wedding Show action.
Here is the relevant code:
wedding_steps_controller.rb
class WeddingStepsController < ApplicationController
include Wicked::Wizard
steps :weddingdetails, :eventdetails
def show
#wedding = Wedding.find(params[:wedding_id])
render_wizard
end
def update
#wedding = Wedding.find(params[:wedding_id])
#wedding.update_attributes(params[:wedding])
render_wizard #wedding
end
end
weddings_controller.rb
def create
#wedding = current_user.weddings.new(params[:wedding])
respond_to do |format|
if #wedding.save
format.html { redirect_to wedding_steps_path(:id => "weddingdetails", :wedding_id => #wedding.id) }
format.json { render json: #wedding, status: :created, location: #wedding }
else
format.html { render action: "new" }
format.json { render json: #wedding.errors, status: :unprocessable_entity }
end
end
end
STEP 1: wedding_steps/weddingdetails.html.erb
<%= simple_form_for(#wedding, :url => wizard_path(wedding_id: #wedding.id), :method => :put, html: { class: 'form-horizontal'}) do |f| %>
<%= f.error_notification %>
<div class="form-inputs">
<div class="formrow center">
<%= f.input :bridename, placeholder: "The Bride's Name", label: false %>
<h2 class="inline"> &</h2>
<%= f.input :groomname, placeholder: "The Groom's Name", label: false %>
</div>
<div class="formrow center">
<%= f.text_field :weddingdate %>
<!-- OLD STYLE DATE FORMAT <%= f.input :weddingdate, label: "Wedding Date" %> -->
<%= f.input :weddingcity, label: "City" %>
<%= f.input :weddingstate, label: "State" %>
</div>
<div class="formrow center">
<%= f.input :url, placeholder: "i.e. 'johnandkate' ", label: false %>
</div>
</div>
<div class="form-actions center">
<%= f.button :submit, value: "Next" %>
</div>
<% end %>
<%= link_to 'skip', next_wizard_path(wedding_id: #wedding.id) %>
STEP 2: wedding_steps/eventdetails.html.erb
EVENT DETAILS STEP <!--PLACEHOLDER FOR NOW -->
Routes.rb
Jobshop::Application.routes.draw do
resources :pins
resources :weddings
resources :wedding_steps
get "users/show"
root :to => 'pages#home'
get 'about' => 'pages#about'
devise_for :admin_users, ActiveAdmin::Devise.config
ActiveAdmin.routes(self)
resources :inviterequests
devise_for :views
ActiveAdmin.routes(self)
devise_for :users
ActiveAdmin.routes(self)
match 'users/:id' => 'users#show'

This line:
<%= simple_form_for(#wedding, :url => wizard_path, :method => :put, html: { class: 'form-horizontal'}) do |f| %>
Should be:
<%= simple_form_for(#wedding, :url => wizard_path(wedding_id: #wedding.id), :method => :put, html: { class: 'form-horizontal'}) do |f| %>
Note the wizard_path(wedding_id: #wedding.id) When you submit the form you should see parameters = {:wedding_id => some_number} in the logs.
Paste the output of the params for the update action if it doesn't work.
Edit:
You should have ":wedding_id" as part of the required url this will make it impossible to even generate a link to that controller unless it has a properly formatted url.
Replace this
resources :wedding_steps
with this
scope "weddings/:wedding_id" do
resources :wedding_steps
end
So now a correct url would look like weddings/83/wedding_steps/weddingdetails. Likely one or more of your view helpers isn't including wedding_id properly and with this new constraint you will raise an error in the view, but this is a good thing since it will show you where the malformed link is.

I tried the solution provided by Schneems, however it is not running completely without errors. I implemented the following way.
Change
resources :wedding_steps
To
scope "weddings/:wedding_id" do
resources :wedding_steps
end
The problem is parameters are displayed as forbidden based on the error that has been thrown as ActiveModel::ForbiddenAttributesError
To get rid off this,
Change
def update
#wedding = Wedding.find(params[:wedding_id])
#wedding.update_attributes(params[:wedding])
render_wizard #wedding
end
To
def update
#wedding = Wedding.find(params[:wedding_id])
#wedding.update_attributes(wedding_params)
render_wizard #wedding
end
private
def wedding_params
params.require(:wedding).permit(........your parameters here.................)
end

Related

Simple form not submitting to database

I'm building a simple online shop for practice and want to track order histories, at the moment I'm getting the user to submit but the shipping address and order history, later I'll upgrade order history to be a hidden field.
The problem is that I can't get the simple form to submit anything to my database.
My form looks like this:
<p class="text-center">
congratulations your order is almost complete, please fill out the form below to place your order or <%= link_to "browse other products.", root_path %>
</p>
<%= simple_form_for #placeorder, html: { multipart: true } do |f| %>
<%= f.error_notification %>
<div class="form-inputs" >
<%= f.input :shipping_address, label: false, placeholder: 'Shipping address', input_html: { class: 'input-lg', required: true } %>
<%= f.input :order_history, label: false, placeholder: 'order_history', input_html: { class: 'input-lg', required: true } %>
</div>
<div class="form-actions">
<%= f.button :submit, "Confirm order" %>
</div>
<% end %>
My place order controller looks like this:
class PlaceOrdersController < ApplicationController
def new
current_order.order_items.each do |order_item|
#last_item_name = order_item.product.name
end
#placeorder = PlaceOrder.new
#order = current_order.order_items
end
def create
#placeorder = PlaceOrder.create(place_order_params)
p "HELLO #{#placeorder}"
if #placeorder.save
flash[:success] = "You've made your order"
redirect_to root_path
else
flash[:alert] = "Something went wrong, check the form and submit your order again"
render :new
end
end
private
def place_order_params
params.require(:place_order).permit(:shipping_address, :order_history)
end
end
My routes.rb looks like this:
Rails.application.routes.draw do
resources :products
resources :checkout
resources :place_orders
resource :cart, only: [:show]
resources :order_items, only: [:create, :update, :destroy], defaults: { format: 'js' }
root to: "products#index"
devise_for :users, :controllers => { registrations: 'registrations' }
end
I have other forms that are working fine and they look the same. Any help would be greatly appreciated.

Resource defines an update using PATCH but app wants POST in Rails 4

I'm trying to add edit functionality to my web app, and am having some trouble. The error page I get back when I try to complete an edit of my Request object indicates that it couldn't find the right route, but the same error page contains a list of routes which includes the route it's looking for. So I'm a bit flummoxed.
The "new" method is almost identical to this edit method and the pages are almost identical as well.
The error page begins No route matches [POST] "/requests/19/edit" and then, partway down the route listing, I see this:
requests_path GET /requests(.:format) requests#index
POST /requests(.:format) requests#create
new_request_path GET /requests/new(.:format) requests#new
edit_request_path GET /requests/:id/edit(.:format) requests#edit
request_path GET /requests/:id(.:format) requests#show
PATCH /requests/:id(.:format) requests#update
PUT /requests/:id(.:format) requests#update
DELETE /requests/:id(.:format) requests#destroy
So Rails seems to be generating a request_path which expects a PATCH, not a POST, right?
routes.rb
Rails.application.routes.draw do
root "pages#index"
resources :destinations
resources :users
resources :manifests
resources :requests
:
request.rb
class Request < ActiveRecord::Base
validates_presence_of :justification
validates_presence_of :required_by
belongs_to :user
belongs_to :manifest
belongs_to :network
has_many :uploaded_files
scope :sorted, lambda{ order("required_by") }
end
edit.html.rb
<% #page_title = "Update Request" %>
<%= link_to("<< Back to List", {:action => 'index'}, :class => 'back-link') %>
<div class="requests edit">
<h2>Update Request</h2>
<%= form_for :request, url: request_path(#request) do |f| %>
<%= render(:partial => "form", :locals => {:f => f}) %>
<div class="form-buttons">
<%= submit_tag("Update Request") %>
</div>
<% end %>
</div>
requests_controller.rb
def update
#request = Request.find(params[:id])
p = {'file' => params[:request][:uploaded_file], 'request_id' => #request.id}
uf = UploadedFile.create(p)
if #request.update_attributes(request_params)
flash[:notice] = "Request updatred succesfully"
redirect_to :action => 'show', :id => #request.id
else
render 'edit'
end
end
What have I missed?
Change
<%= form_for :request, url: request_path(#request) do |f| %>
to
<%= form_for :request, url: request_path(#request), method: :patch do |f| %>
in your edit.html.erb
form_for(as you are using it) sets POST as default HTTP verb. You need to alter it by setting method :patch which responds to the update action.
You can simplify it to just
<%= form_for #request do |f| %>
Check the APIdoc for more Info.

csv uploader throwing nil or empty error

I have a site that has an a table called orders, the order model, and a csv_files_controller (separate from the orders controller).
in the model I have the following:
def self.import(csv_file)
CSV.foreach(csv_file.path, headers: true) do |row|
Order.create! row.to_hash
end
end
in the csv_files_controller I have the following:
class CsvFilesController < ApplicationController
def new
#csv_file = CsvFile.new
end
def create
#csv_file = CsvFile.new(params[:csv_file])
if #csv_file.save
Order.import
redirect_to csv_file, notice: "Orders uploaded successfully"
end
end
def show
#csv_file = CsvFile.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.json { render json: #csv_file }
end
end
end
my upload_form partial being rendered by a page in the orders views from csv_files views:
<%= form_for #csv_file do |f| %>
<div class="controls">
<%= f.file_field :csv_file, accept: 'csv', :class => 'btn btn-xs btn-info' %>
<%= f.submit "Upload Orders", :class => 'btn btn-xs btn-success' %>
</div>
<% end %>
my routes.rb also has
resources :csv_files
when I try to load the page for the uploading I am getting a First argument in form cannot contain nil or be empty error. I am not sure what I have done wrong for it to say that.
Now if I change the form_for to :csv_files the page will load, but it is blank; no browse for file or submit button appear, but the error goes away. Doesn't matter though if the form isn't working. I am using rails 4 so I shouldn't need he :html => {multipart: true} and even when it was there it didn't change anything.
I can't figure out why it is throwing the error.
Update 9-1-15:
I have made a ton of changes, but now I get
No route matches [POST] "/orders/upload_page"
but my rake routes shows I have set my post route to :import.
resources :orders do
collection do
post :import
get :upload_page, as: 'upload_page'
get :search, as: 'search'
get :csv_report, as: 'csv_report'
get :overdue_csv_report, as: 'overdue_csv_report'
end
end
I don't understand why it is routing post to the upload_page.
The answer was threfold:
I got rid of the csv_files controller, etc. and moved all the code to the original orders controller.
I was trying to use a form_for .... do |f| and I had to revert to form_tag .... do for the form and spell everything out to get the post to work.
code snips:
Model:
def self.import(csv_file)
CSV.foreach(csv_file, headers: true) do |row|
Order.create! row.to_hash
end
end
Controller:
def import
Order.import(params[:csv_file].tempfile)
redirect_to orders_path, notice: "Orders imported"
end
form partial:
<%= form_tag import_orders_path, multipart: true do %>
<div class="controls">
<%= file_field_tag :csv_file, accept: 'csv', :class => 'btn btn-xs btn-info' %>
<%= submit_tag "Upload Orders", :class => 'btn btn-xs btn-success' %>
</div>
<% end %>
Routes:
resources :orders do
collection do
post :import
I am now working on ensuring that the uploads are using the validations in the model as it seems to be skipping it.

Undefined method which is not used

Hello i'm new one in ruby on rails. I have strange problem. I use some tutorial and get error which i shouldn't get.
I have controller
class DiaryController < ApplicationController
before_action :authenticate_user!
respond_to :html, :xml, :json
respond_to :js, :only => [:create, :update, :destroy]
def create
#record = Record.create(record_params)
#record.userId=current_user.id
if request.xhr? || remotipart_submitted?
sleep 1 if params[:pause]
render :layout => false, :template => (params[:template] == 'escape' ? 'comments/escape_test' : 'diary/create'), :status => (#record.errors.any? ? :unprocessable_entity : :ok)
else
redirect_to diary_path
end
end
def add
#record = Record.new
#respond_with(#record, :layout => false)
respond_with do |format|
format.html { render :layout => ! request.xhr? }
end
end
# PUT /comments/1
# PUT /comments/1.xml
def update
#record = Record.find(params[:id])
respond_with do |format|
format.html{ redirect_to #record }
end
end
def delete
#comment = Comment.destroy(params[:id])
end
def edit
#record = Record.find(params[:id])
end
def index
#records = Record.where(userId: current_user.id)
end
private
def record_params
params.require(:record).permit(:photo, :comment, :date, :photo_cache)
end
end
Have view
<h1 align="centre">
Добавить запись
</h1>
<%= render 'form' %>
<%= link_to 'Отмена', diary_path, :id => 'cancel-button' %>
and
<%= form_for(#record, :remote => (params[:action] == 'add' ? true : false)) do |f| %>
<fieldset>
<div class="field">
<%= f.label :date, :class => 'required' %><br />
<%= f.date_select :date %>
</div>
<div class="field">
<%= f.label :comment %><br />
<%= f.text_area :comment %>
</div>
<div class="field">
<%= image_tag(#record.photo_url(:thumb)) if #record.photo? %><br />
<%= f.label :photo %><br/>
<%= f.file_field :photo %><br/>
<%= f.hidden_field :photo_cache %>
</div>
</fieldset>
<table>
<tr>
<td>
<div class="actions">
<%= f.submit "Добавить", :data => {:'disable-with' => "Submitting..."} %>
</div>
</td>
<td>
<%= link_to 'Отмена', diary_path, :id => 'cancel-button' %>
</td>
</tr>
</table>
And get ActionView::Template::Error (undefined method `records_path' for #<#:0x000000054461c8>): error on "<%= form_for(#record, :remote => (params[:action] == 'add' ? true : false)) do |f| %>" line. Even records_path i did'n use.
I Have routes
devise_for :users
get 'welcome/index'
root 'welcome#index'
get 'diary' => 'diary#index'
get 'diary/add_record', to: 'diary#add', as: 'add_record'
post 'diary/add_record', to: 'diary#create'
get 'diary/edit_record/:id', to: 'diary#edit'
delete 'diary/edit_record/:id' => 'diary#delete
And and try to use add_record route. Maybe it would be better to use resources :records.But i want to figure out why my routes doesn't work.
view name "diary".
Because you're new to RoR, let me explain why you're receiving the error
form_for
form_for is the likely reason why you're receiving this error (oh, I just saw it actually states this is where the error occurs - sweet)
The problem you have is that form_for is meant as a way to render a form around an ActiveRecord object. It's mean to give some semi-persistence to the data, by using AR in both the new and create actions (allowing you to show the in-putted data on the form after submission)
When you pass an object to form_for, Rails automatically "builds" the form from the ActiveRecord object, one of the options it uses being the url
--
Routes
The problem you have is the object you pass to the form_for takes the model_name attribute to build the route. This means if you want to use the form_for method by just passing an object, it's going to look for routes pertaining directly to that object
If you don't have any [model]_path route set up, you'll likely receive the error you're getting. The fix firstly involves the routes, and secondly involves the controller:
#config/routes.rb
root 'welcome#index'
devise_for :users
resources :diary, path_names: { new: "add_record", create: "add_record", edit: "edit_record", destroy: "edit_record" }
resources :welcome, only: :index
This is down to the idea that Rails' routing structure is built around resources - every route you have should lead to a specific controller action. Whilst including custom actions is completely fine, you have to appreciate that the basis of the routing structure is to construct resourceful routing, which essentially means that Rails perceives every controller / model to have corresponding routes:
--
URL
The second thing to observe is the url of the form
If you have your routes set up as above, and if your routing structure differs from your model structure (different names), you'll want to use the following setup to define the url explicitly:
<%= form_for #record, url: your_custom_path do |f| %>

Mail_form : "No Route Matches [POST]" - Routing Error

Rails 3.2
I use the Mail_form gem (from plataformatec) to create a simple 'contact us' form for my website. When click on 'send' I get a routing error that says:
Routing Error
No route matches [POST] "/contactus"
Try running rake routes for more information on available routes.
I have a very simple setup, but I am new to Rails and am still getting the hang of it. I only want the form to send an email to a certain email address... nothing else. I understand the problem is in routes.rb but I have been fiddling with this for so long I just can't figure out what is wrong. I have never struggled with a Rails error so much. PLEASE HELP!
'Pages' Model: app/models/pages.rb
class Page < MailForm::Base
attribute :name, :validate => true
attribute :email, :validate => /\A([\w\.%\+\-]+)#([\w\-]+\.)+([\w]{2,})\z/i
attribute :page_title, :validate => true
attribute :page_body, :validate => true
def headers
:subject => "#{page_title}",
:to => "careers#example.com",
:from => %("#{name}" <#{email}>)
end
end
'Pages' Controller: app/controllers/pages_controller.rb
class PagesController < ApplicationController
respond_to :html
def index
end
def create
page = Page.new(params[:contact_form])
if page.deliver
redirect_to contactus_path, :notice => 'Email has been sent.'
else
redirect_to contactus_path, :notice => 'Email could not be sent.'
end
end
end
Form Partial: app/views/pages/_form.html.erb
<%= simple_form_for :contact_form, url: contactus_path, method: :post do |f| %>
<div>
<%= f.input :name %>
<%= f.input :email, label: 'Email address' %>
<%= f.input :page_title, label: 'Title' %>
<%= f.input :page_body, label: 'Your message', as: :text %>
</div>
<div class="form-actions">
<%= f.button :submit, label: 'Send', as: :text %>
</div>
View (called contactus): app/views/pages/contactus.html.erb
<body>
<div>
<h2 class="centeralign text-info">Contact Us</h2>
</div>
<div class="container centeralign">
<%= render 'form' %>
</div>
<h2>We'd love to hear from you! </h2><br /><h4 class="muted">Send us a message and we'll get back to you as soon as possible</h4>
</div>
</div>
</body>
Routes.rb
Example::Application.routes.draw do
resources :pages
root to: 'pages#index', as: :home
get 'contactus', to: 'pages#contactus', as: :contactus
get 'services', to: 'pages#services', as: :services
Your routes.rb file doesn't have a route for POST /contactus
You've got a route for GET /contactus but no POST, so what rails is saying is correct.
Just add something like
post 'contactus', to: 'controller#action'
With whatever controller and action you need to call. Alternatively, if you're trying to call the create action in the pages controller, then your problem is that where you've added resources :pages to routes, you've actually create the route
post 'pages'
So in that case, I'd change your simple_form_for url to post to there instead. Try using
simple_form_for :contact_form, url: pages_path, method: :post do
instead. If pages_path doesn't work, then just run rake routes in a console and you'll see a list of all of the routes you have including their names. Then just pick the one you need for this :)

Resources