observe_form url confusion - ruby-on-rails

i cannot seem to get observe_form to call a particular action
i have a route defined
map.resources :charges, :collection => {:charge_total => :get}
my controller
class ChargesController < ApplicationController
def charge_total
return 'foo'
end
end
my view: i have tried both...
observe_form form_id, :update => :charge_total, :url => :charge_total_charges
and
observe_form form_id, :update => :charge_total, :url => {:controller => :charges, :action => :charge_total}
when the form updates, i get an unknown action error
No action responded to update. Actions: charge_total, create
it sees that there is an action charge_total, however it is trying to respond to update? im not sure what is going on. any thoughts?

bahh!
put, not get...
map.resources :charges, :collection => {:charge_total => :put}

Related

Couldn't find [model] without an ID - Ruby on rails

I have multiples forms in the Edit view like you can see below:
View
-#posts.each do |post|
.form
= simple_form_for post, url: update_posts_path do |f|
= f.input :title
= f.submit
Then when I'm updating any form I get this error 'Couldn't find Pots without an ID'. You can see the controller and the routes file here:
Controller
def update
#post = Posts.find(params[:id]) //If I change it for Posts.first then is working
if #post.update_attributes(params.require(:posts).permit(:title))
redirect_to ....
else
flash[:notice] = "Sorry."
render :edit
end
end
Routes File
resources :posts, :only => [:index, :edit, :update] do
get "edit", :on => :collection, :as => :edit
patch "update", :on => :collection, :as => :update
end
I think that the error is that for some reason this (#post = Posts.find(params[:id])) is returning a nil object then the controller can't update it. Can someone give me a hand?
The error is the :on => :collection part. This allows the action to be called without an id, so params[:id] is empty.
:on => :collection is normally used for index like actions that have a set of records as a result, so don't need the id part.
btw: the whole thing:
get "edit", :on => :collection, :as => :edit
patch "update", :on => :collection, :as => :update
is redundant, the first line:
resources :posts, :only => [:index, :edit, :update]
tells Rails everything it needs.
For update action you are using :on => :collection but your request is put/patch request so you will use patch "update", :on => :member, :as => :update also make changes in form_for as per your route.Use<%=simple_form_for post ,:url=> update_post_path(post) do |f| %> instead of url: update_posts_path
Regarding params.require(:posts).permit(:title)
First problem : you are using posts instead of post
second is Parameter :id is missing
you will use params.require(:post).permit(:title,:id) instead of params.require(:posts).permit(:title)

Rails: form for different controller

I'm developing a rails app with a landingpage. On the landingpage, the user can sign up for the app. For login, there is an extra view with an extra controller.
It looks like this:
views/landinpage/index.html --> sign up form
views/login/index.html --> login form
but I only want to have one controller
controllers/login_controller --> create new user from sign up form & check login data
so I have to get a connection between the landingpage view and the login_controller.
This is my attempt:
<%= form_for #login, :url => { :controller => "login_controller", :action => "create" }, :html => {:method => :post} do |f| %>
but it throws a route error:
No route matches {:controller=>"login_controller", :action=>"create"}
I already defined login resources in routes.rb, but it seems that the problem is elsewhere?
resources :logins
any ideas?
try this
class LoginsController < ApplicationController
def new
...
end
def create
...
end
...
end
in your route.rb file write
match '/login/create' => 'logins#create', :as => :create_login
or
resources :logins
in your console - write - rake routes and check your routes
then
<%= form_for #login, :url => create_login_path(#login) do |f| %>
I think your code should look like this:
<%= form_for #login, :url => { :controller => "login", :action => "create" }, :html => {:method => :post} do |f| %>
can't test this right now, but I believe the _controller part is not required.
Update:
Another thing that I'm using a lot and that works:
<%= form_for #login, :url => create_login_path(#login), :html => {:method => :post} do |f| %>
You may have to fix the create_login_path part to match your application's routes but that's how I usually define these views.
Try this
class LoginsController < ApplicationController
def new
...
end
def create
...
end
...
end
in your routes.rb file
resources :logins do
collection do
post :create
end
end
and in your views
<%= form_for #login, :url => create_login_path(#login) do |f| %>>
you can see the html form action part, you can see!
your config/routes has
resources :posts
namespace :admin do
resources :posts
end

Undefined method with "_path" while using rails form_for

I'm running into a (I think) routing error while using the Rails form_for helper. I have been searching around and looked at this question, but the plural for "static_event" with pluralize is "static_events" so I am at a loss. Any help would be apprecited. Here are the details....
ActionView::Template::Error (undefined method `static_events_path' for #<#<Class:0x007f9fcc48a918>:0x007f9fcc46fa78>):
My Model:
class StaticEvent < ActiveRecord::Base
attr_accessible :content, :title, :discount, :location, :day_of_week, :start_time
My Controller:
class StaticEventsController < ApplicationController
before_filter :authenticate, :only => [:create, :destroy]
before_filter :authorized_user, :only => [:destroy]
def new
#title = "Share An Event"
#static_event = StaticEvent.new
end
def create
#static_event = current_user.static_events.build(params[:event])
if #static_event.save
flash[:success] = "Event Shared"
redirect_to #static_event #this was the old version
else
render :new
end
end
The route:
match '/static-events/new', :to => 'static_events#new'
match '/static-events/', :to => 'static_events#index'
match '/static-events/:id', :to => 'static_events#show'
The view
<%= form_for (#static_event) do |f| %>
<%= render 'shared/error_messages', :object => f.object %>
<%= text_field "static_event", "title", "size" => 48 %>
<%= time_select "static_event", "start_time", {:ampm => true, :minute_step => 15} %>
<%= text_area "static_event", "content", "cols" => 42, "rows" => 5 %>
<%= text_field "static_event", "discount", "size" => 48 %>
<%= text_field "static_event", "location", "size" => 48 %>
<%= text_field "static_event", "day_of_week", "size" => 48 %>
<input name="" type="submit" class="button" value="share on chalkboard" />
<% end %>
Only routes created using the resources method are automatically named.
If you want to name your routes, use the :as option:
match '/static-events/new', :to => 'static_events#new', :as => :new_static_event
match '/static-events/', :to => 'static_events#index', :as => :static_events
match '/static-events/:id', :to => 'static_events#show', :as => :static_event
However, it's better to use the resources method. You must pass the "true" name of your model as the first parameter, then override the path if you want:
resources :static_events, :path => 'static-events'
First of all, you should define your routes this way:
resources 'static-events', :only => [:new, :create]
This will create a route for new and create methods.
Because when you use a new ActiveRecord object as an argument to form for, it will looks for *s_path like static_events_path in your routes file with the POST verb.
I think the way you have defined your routes doesn't create the static_events_path with POST verb (you can check that by using rake routes as megas said). So don't use match anymore, use resources or get/post/... instead of match in your Rails 3 projects.
EDIT
I did not notice yesterday, but there is no route for create method. Add the route below before static_events#index or remove all your routes and do like I said above.
post '/static-events/', :to => 'static_events#create'
Run rake routes and you'll see the list of your routes. Then you can fix the route file to have appropriate route path.
This happened to me when i was using a nested resource, but forgot to actually initialize the parent resource using load_and_authorize_resource in cancan. Therefore, the parent resource was null and it threw this error.
I fixed it by declaring load_and_authorize_resource on the parent in the controller.

Rails: Mapping Conflicting Routes by Detecting Param

Hey! I am trying to set up routes in a Rails application so that, depending on the type of parameter passed, Rails sends the request to a different action.
I have courses which have an attribute state which is a string with a two letter state abbreviation. When a user visits /courses/1, I want Rails to display the show action in the courses controller (and pass the parameter as :id). When a user visits /courses/CO though, I want Rails to display the index action and pass the parameter as :state.
So /courses/1 would be equivalent to
:controller => 'courses', :action => 'show', :id => '1'
And /courses/CO would be equivalent to
:controller => 'courses', :action => 'index', :state => 'CO'
I have tried this:
map.resources :courses, :except => { :index, :show }
map.connect 'courses/:state', :controller => 'courses', :action => 'index', :state => /[A-Z]{2}/
map.connect 'courses/:id', :controller => 'courses', :action => 'show', :id => /[0-9]+/
But it breaks (the rails server wont even start). I don't usually do things like this with routes, so I am outside of my know-how. Thanks!
Edit: Fixed a typo, thanks JC.
Current solution looks like this:
map.resources :courses, :except => [ :index, :show ]
map.courses '/courses', :controller => 'courses', :action => 'index', :state => 'AL', :method => :get
map.courses '/courses/:state', :controller => 'courses', :action => 'index', :requirements => { :state => /[A-Z]{2}/ }, :method => :get
map.course '/courses/:id', :controller => 'courses', :action => 'show', :requirements => { :id => /[0-9]+/ }, :method => :get
This works, but you will need to go edit all your links to the index to say things like courses_path('AA') and you won't be able to use some of the nice helpers, like form_for, which assume you are following the convention that #create is simply #index with a POST request. (Get comfortable with form_tag)
ActionController::Routing::Routes.draw do |map|
map.resources :courses, :except => [ :index, :show ]
map.courses '/courses/:state', :controller => 'courses', :action => 'index', :requirements => { :state => /[A-Z]{2}/ } , :method => :get
map.course '/courses/:id', :controller => 'courses', :action => 'show', :requirements => { :id => /[0-9]+/ } , :method => :get
end
It will keep your routes named the same, though.
(by the way, your /co does not match your regex, which requires upper case chars)
Fun aside: Do we really need the abstraction of a router? http://blog.peepcode.com/tutorials/2010/rethinking-rails-3-routes
I'm afraid this won't work since the structure that maps paths to controllers and actions is setup on start of the rails application, parameter handling happens at request time.
What you could do is to match the :id-parameter in the show-action of the CoursesController against a list of valid states and then either redirect or render a different action.
Hope this helps.

Problem with link_to_remote in rails

I'm having a consistency problem using link_to_remote in rails.
I have 2 use cases of link_to_remote, and they generate different ajax. I can't figure out why, and it is driving me crazy.
Here is use case one...
<%= link_to_remote "section-", :update => "sections", :url => {:action => :destroy, :controller => "sections", :id => #section.id } %>
This generates the appropriate ajax (as below) and works as I expect. Note that it picks up the :action param from the call and inserts it correctly in the ajax.
section-
I also have another instance where I use link_to_remote, but it generates incorrect ajax. The use case is nearly identical, except the controller is different. Either way, I wouldn't expect that to result in different ajax.
The call...
<%= link_to_remote "question-", :update =>"questions-1", :url => {:action => :destroy, :controller => "questions", :id => #question.id} %>
The resulting ajax...
question-
The obvious difference here is in the second arg to Ajax.Updater. The :action param is missing from that path. Why? This results in broken code for me, but I can't understand why this is happening. The link_to_remote calls are nearly identical.
Please point me in the right direction. Thanks.
Below is my routes.rb file...
ActionController::Routing::Routes.draw do |map|
map.resources :questions, :has_one => :section, :collection => { :sort => :post }
map.resources :sections, :has_many => :questions, :has_one => :form, :collection => { :sort => :post }
map.resources :forms, :has_many => :sections
# You can have the root of your site routed with map.root -- just remember to delete public/index.html.
map.root :controller => "forms"
map.connect ':controller/:action/:id'
map.connect ':controller/:action/:id.:format'
end
What do you get if you copy this into your view?
<%= url_for :action => :destroy, :controller => :questions, :id => #question.id %>
I suspect the problem's not really with link_to_remote, but with routing. Once url_for is returning the URL you expect, then try link_to_remote again.
Simply adding a :method => :delete to your link_to_remote call may be the simplest fix for you:
<%= link_to_remote "question-", :update =>"questions-1", :url => {:action => :destroy, :controller => "questions", :id => #question.id}, :method => :delete %>
This should force the call to /questions/:id to use the HTTP DELETE method. If you want the above call to generate the url /questions/destroy/:id instead I believe you would need a manual change to your routes, as the default map.resources doesn't seem to be achieving that result.

Resources