I have a RESTful controller inside of a namespace called dashboard, so my URL looks like this:
/dashboard/member
/dashboard/member/edit
Something weird is happening when I submit the member form with a validation error... it shows the error like it's suppose to, but when it goes to the PATCH url "/dashboard/member" it comes with an ".2" in the end:
/dashboard/member.2
the "2" is the ID of the record.
The funny thing is that I did everything correctly and it works great, this ".2" is the only thing that is bothering my head.
My Controller
class Dashboard::MembersController < ApplicationController
load_and_authorize_resource :class => Member
before_filter :authenticate_member!
def show
end
def edit
#member ||= current_member
end
def update
#member ||= current_member
if #member.update_attributes(member_params)
flash[:success] = "Profile updated"
redirect_to dashboard_member_path
else
render "edit"
end
end
private
def member_params
params.require(:member).permit(:first_name, :last_name, :address, :city, :state, :country, :zipcode, :home_phone, :cell_phone)
end
end
My Route
namespace :dashboard do
resource :member, only: [:show, :edit, :update]
end
If you meant to use resource :member (instead of resources :member) then you should know that it always looks up without referencing an ID.
Here is how the routes would be created without id's:
edit_dashboard_member GET /dashboard/member/edit(.:format) dashboard/members#edit
dashboard_member GET /dashboard/member(.:format) dashboard/members#show
PATCH /dashboard/member(.:format) dashboard/members#update
PUT /dashboard/member(.:format) dashboard/members#update
When you are sending a PATCH request make sure that you don't pass an argument with it. If you pass an argument then it would be interpreted as format(like .html, .js etc). In your case you passed an argument as 2 or a member with an id 2
For eg:
PATCH request to dashboard_member_path(2)
The route was matched against PATCH /dashboard/member(.:format) dashboard/members#update
2 is interpreted as (.:format) because there is no :id part.
I had to remove the #member from my form, so... I had this:
<%= form_for(#member, url: dashboard_member_path(#member), html: {method: "patch", class: "form-horizontal"}) do |f| %>
And it became this:
<%= form_for(#member, url: dashboard_member_path, html: {method: "patch", class: "form-horizontal"}) do |f| %>
Now, there's IDs being passed to the URL.
Thanks guys!
Related
I'm having a hard time trying to get setup some custom form objects in a new Rails 6 project I am building. I suspect this may be due to namespacing issues but I can't yet tell for sure.
app/views/saasy/signups/new.html.erb
<%= form_with(model: [ :saasy, #signup ], url: saasy_signups_path(#signup), local: true) do |signup_form| %>
<%= fields_for :account, #signup.account do |account_fields| %>
Organization name: <%= account_fields.text_field :organization %>
<% end %>
<%= signup_form.submit %>
<% end %>
app/controllers/saasy/signups_controller.rb
class Saasy::SignupsController < ApplicationController
def new
#signup = Saasy::SignupForm.new
end
def create
#signup = Saasy::SignupForm.new(signup_form_params)
#signup.register
end
private
def signup_form_params
params
.require(:saasy_signup_form)
.permit(account_attributes: [:organization])
end
end
config/routes.rb
Rails.application.routes.draw do
namespace :saasy do
resources :signups, only: [:new, :create]
end
end
app/forms/saasy/signup_form.rb
module Saasy
class SignupForm
include ActiveModel::Model
attr_accessor :user, :account
delegate :attributes=, to: :user, prefix: true
delegate :attributes=, to: :account, prefix: true
def initialize(params= {})
super(params)
#user = Saasy::User.new(params)
#account = Saasy::Account.new(params)
end
def register
# eventually do actual signup stuff here
end
end
end
However, whenever I test it I get back the following message: param is missing or the value is empty: signup_form
The params hash looks like this:
{
"authenticity_token"=>"BhhvRaYKf220afExocQ//LIY1jszVsXs+lThFeUFKvr6ciVBsa+22mSxwO3yT6mK2uOsWSCKx9gL6WIaGmmvSg==",
"account"=>{"organization"=>"Example Name"},
"commit"=>"Create Signup form"
}
I've tried a whole lot of general messing around solutions like playing with the form_with in the view and changing route names etc but I've not had any luck so far. Any advice would be really appreciated!
This doesn't have anything to do with namespaces. You're just requiring the wrong param key.
def signup_form_params
params
.require(:signup_form)
.permit(account_attributes: [:organization])
end
Rails gets the "key" for the inputs by calling model_name.param_key on the model that you pass. The param key does not take into account the module nesting of the class. Neither should it really as thats an implementation detail and not nessicarily part of the "public api" that your app exposes via HTTP. Your code organization and the routes / http parameters of your application are two very different things.
You can override the key by providing the scope: option to form_with.
<%= form_with(model: [ :saasy, #signup ], scope: :saasy_signup_form, local: true) do |signup_form| %>
<%= fields_for :account, #signup.account do |account_fields| %>
Organization name: <%= account_fields.text_field :organization %>
<% end %>
<%= signup_form.submit %>
<% end %>
But IMHO its just silly.
So as it stands I have a form partial which starts off as:
<%= form_for(#merchandise) do |f| %>
It works perfectly for editing the data that I have already assigned in the rails console. When I try to use it for a "new" form that creates new merchandise (in this case the singular form of merchandise, I don't have nested resources, multiple models etc.), I get a no Method error that states
"undefined method 'merchandises_path' for #<#<Class:0x64eaef0>:0x95d2370>".
When I explicitly state the URL in the form_for method:
<%= form_for(#merchandise url:new_merchandise_path) do |f| %>
I get it to open and I finally have access to the form, however in this case I get a routing error that states
"No route matches [POST] "merchandise/new"".
I decided to write out that route in my routes file which previously just had:
root "merchandise#index" resources :merchandise
After I add the route it literally does nothing. I click submit and it takes me to the form but there is no new data in the database. I am at a complete loss and have been at this for hours googling and stack overflowing and I just don't know what to do anymore. All help is seriously appreciated. I'm adding a pastebin with all my code in the following url:
http://pastebin.com/HDJdTMDt
I have two options for you to fix it:
Option 1:
Please try to do this for best practice in Rails:
routes.rb
change your routes use plural
resources :merchandises
merchandises_controller.rb
Rename your file controller and class into MerchandisesController
class MerchandisesController < ApplicationController
def index
#merchandise = Merchandise.all
end
def new
#merchandise = Merchandise.new
end
def create
#merchandise = Merchandise.new(merchandise_params)
if #merchandise.save
redirect_to merchandises_path
else
render :new
end
end
def show
#merchandise = Merchandise.find(params[:id])
end
def edit
#merchandise = Merchandise.find(params[:id])
end
def update
#merchandise = Merchandise.find(params[:id])
if #merchandise.update(merchandise_params)
redirect_to #merchandise, notice: "The movie was updated"
else
render :edit
end
end
def merchandise_params
params.require(:merchandise).permit(:shipper, :cosignee, :country_arrival_date, :warehouse_arrival_date, :carrier, :tracking_number, :pieces, :palets, :width, :height, :length, :weight, :description, :cargo_location, :tally_number, :customs_ref_number, :released_date, :updated_by, :country_shipped_to, :country_shipped_from)
end
end
Option 2:
If you want to not change many code
/merchandise/_form.html.erb
in partial file
/merchandise/new.html.erb
<%= render 'form', url: merchandise_path, method: 'post' %>
/merchandise/edit.html.erb
<%= render 'form', url: category_path(#merchendise.id), method: 'put' %>
Straight to the point, a bit confusing here
this is my code
routes.rb
Rails.application.routes.draw do
namespace :main, path: ':master_url' do
root 'sites#index'
namespace :dashboard do
root 'dashboards#index'
resources :masters
end
get "/:action" => 'sites#:action'
end
root 'main/sites#index'
end
rake routes
Prefix Verb URI Pattern Controller#Action
main_root GET /:master_url(.:format) main/sites#index
main_dashboard_root GET /:master_url/dashboard(.:format) main/dashboard/dashboards#index
main_dashboard_masters GET /:master_url/dashboard/masters(.:format) main/dashboard/masters#index
POST /:master_url/dashboard/masters(.:format) main/dashboard/masters#create
new_main_dashboard_master GET /:master_url/dashboard/masters/new(.:format) main/dashboard/masters#new
edit_main_dashboard_master GET /:master_url/dashboard/masters/:id/edit(.:format) main/dashboard/masters#edit
main_dashboard_master GET /:master_url/dashboard/masters/:id(.:format) main/dashboard/masters#show
PATCH /:master_url/dashboard/masters/:id(.:format) main/dashboard/masters#update
PUT /:master_url/dashboard/masters/:id(.:format) main/dashboard/masters#update
DELETE /:master_url/dashboard/masters/:id(.:format) main/dashboard/masters#destroy
main GET /:master_url/:action(.:format) main/sites#:action
root GET / main/sites#index
main/dashboard/masters_controller.rb
class Main::Dashboard::MastersController < ApplicationController
before_action :all_masters, only: [:index, :create, :update, :destroy]
before_action :set_master, only: [:edit, :update, :destroy, :show]
before_action :init_master
layout 'main'
respond_to :html, :js
def new
#master = Master.new
end
def create
#master = Master.create(conf_params)
end
def edit
end
def update
#master.update_attributes(conf_params)
end
def destroy
#master.destroy
end
private
def all_masters
#masters = Master.all
end
def set_master
#master = Master.find(params[:id])
end
def conf_params
params.require(:master).permit(:title,:url)
end
def init_master
#master_url = Master.find_by_url(params[:master_url])
end
end
this is what i did when partially render _form_master.html.erb , which i called on new.js.erb and edit.js.erb
$('#form-master').html("<%= j (render 'form_master', :master => #master) %>");
_form_master.html.erb contents
<%= simple_form_for [:main, :dashboard, #master], remote: true do |f| %>
<%= f.input :url, label: 'URL' %>
<%= f.input :title, label: 'Title' %>
<%= f.button :submit %>
<% end %>
PROBLEMS:
When i called new master, with this
<%= link_to new_main_dashboard_master_path, remote: true do %>
the page rendered flawlessly, and create master doing good
but when i called edit , with this line
<%= link_to :controller=>"masters",:action =>"edit",:id => master do %>
which was my problem earlier , rails returning an error with messages:
ActionView::Template::Error (No route matches {:action=>"show", :controller=>"main/dashboard/masters", :format=>nil, :id=>nil, :master_url=>#<Master id: 4, url: "test", title: "Test Aja", created_at: "2015-02-02 08:55:07", updated_at: "2015-02-02 08:55:07">} missing required keys: [:id]):
i am explicitly render values of master.id and master.title to the page, which is returning correct values.
Q: How do i fix this ? i was trying a couple of times, from changing the locals pass on js.erb, change the #model to just model, still not work
Any help are appreciated, thanks ! :)
Here we have post = Post.find(params[:post_id])
from http://blog.8thcolor.com/en/2011/08/nested-resources-with-independent-views-in-ruby-on-rails/
Don't you have anything like that for your model?
You need an :id of some kind don't you?
This may be out of context but I'm not going to try to reuse your code.
And it may be too simple to try something like
render plain: params[:someparam].inspect
but it helps me.
http://codefol.io/posts/Deep-Rails-Understanding-HashWithIndifferentAccess-Understanding-the-Params-Hash
I have an object that I am trying to allow users to edit in my rails 4 app. The user has_one supp_form and I want them to be able to edit the information in the supp_form. The page is loading fine and the relationships are setup properly.
The error
No route matches [PATCH] "/businesses/3/supp_form/edit"
when I rake routes I see the following route:
edit_business_supp_form_path GET /businesses/:business_id/supp_form/edit(.:format) supp_forms#edit
GET /businesses/:business_id/supp_form(.:format) supp_forms#show
PATCH /businesses/:business_id/supp_form(.:format) supp_forms#update
PUT /businesses/:business_id/supp_form(.:format) supp_forms#update
supp_forms_controller.rb
class SuppFormsController < ApplicationController
before_filter :authenticate_user!
def new
#suppform = SuppForm.new(supp_form_params)
end
def create
#suppform = SuppForm.create(supp_form_params)
end
def edit
#user = User.current_user
#suppform = #user.supp_form
end
def update
#user = current_user
#suppform = SuppForm.update(supp_form_params)
end
private
def supp_form_params
params.require(:supp_form).permit(:id, :business_id, :title, :first_name,
:last_name, :applicant_role, :work_phone_number)
end
end
View
<%= form_for #user.supp_form, :url => edit_business_supp_form_path(#user.supp_form), :html => { :class => "sky-form", :id => "sky-form4" } do |supp_form| %>
<%= supp_form.text_field :work_phone_number, :placeholder => "Your new phone number" %>
<% end %>
The problem is that it tries to access the route using a PATCH request, that is used for updating. In your routes the /businesses/:business_id/supp_form/edit route is only specified for GET requests, thus the error.
This happens because the path you are using in the form points to the edit action (which is only responsible for showing the edit form) and should instead point to the update action. So the route you should be actually using in the is the supp_form_path that, in connection with the PATCH method, pushes the information to the update action, where the object is updated.
Route
resources :cars do
collection do
get :f01a
end
end
Controller
class CarsController < ApplicationController
def f01a
#user = User.find(params[:id])
#count = Count.find_by_user_id(#user)
#count.increment!(:f02)
redirect_to #user
end
end
View
<%= button_to "add f01", f01a_cars_path %>
I can't get this to work. I need to execute this code from a button.
button_to sends a POST request, but your routing is setup to only accept GET requests. You should change it to:
resources :cars do
collection do
post :f01a
end
end
Since you're using params[:id] in your action, but not sending it in at all, you'll need to pass it in your button_to:
<%= button_to "add f01", f01a_cars_path(:id => something)
(Replace something with whatever ID you want to pass.)