Why form_for use incorrect REST url_helpers for namespaced controller? - ruby

In my rails app have a partial that contains a form shared between the new and edit action:
<%= form_for #customer do |f| %>
....
<% end %>
These action are of a controller (called customers) namespaced (called admin), if try to run the code show the error when execute form_for:
undefined method `customer_path'
Have resolved this using:
<%= form_for :customer, #customer do
|f| %>
....
<% end %>
Now the form is generated with correct url when is called by new action but when generated by edit the form url is "/admin/customers/1/edit" instead of update. If submit the form show the error:
No route matches "/admin/customers/1/edit"
but in routes.rb have:
namespace :admin do
resources :customers
end
and rake:routes show all the REST urls:
admin_customers GET /admin/customers(.:format) {:action=>"index", :controller=>"admin/customers"}
POST /admin/customers(.:format) {:action=>"create", :controller=>"admin/customers"}
new_admin_customer GET /admin/customers/new(.:format) {:action=>"new", :controller=>"admin/customers"}
edit_admin_customer GET/admin/customers/:id/edit(.:format){:action=>"edit",:controller=>"admin/customers"}
admin_customer GET /admin/customers/:id(.:format) {:action=>"show",:controller=>"admin/customers"}
PUT /admin/customers/:id(.:format) {:action=>"update", :controller=>"admin/customers"}
DELETE /admin/customers/:id(.:format) {:action=>"destroy",:controller=>"admin/customers"}
Any idea?

Try this
<%= form_for [:admin, #customer] do |f| %>

Related

redirect to another URL using submit button in ruby

I have submit button and i want to redirect in another URL (hard coded) this URL
https://www.ccavenue.com/shopzone/cc_details.jsp
my code :
<%= form_tag #ccavanue do |f| , url => "https://www.ccavenue.com/shopzone/cc_details.jsp", :html => :method => "put" %>
<%= hidden_field_tag :my_field, #MerchantId, :id => 'merchant_id' %>
<%= submit_tag "Click Me" %>
<% end %>
i want to redirect another website URL with this submit button . please guided me.
Change your code to following:
<%= form_for #ccavanue, url: "https://www.ccavenue.com/shopzone/cc_details.jsp" do |f| %>
<%= f.hidden_field :my_field, #MerchantId, :id => 'merchant_id' %>
<%= f.submit "Click Me" %>
<% end %>
In Rails a form is designed to create or update a resource and reflects the identity of the resource in several ways:
The url that the form is sent to (the form element's action attribute) should result in a request being routed to the appropriate controller action (with the appropriate :id parameter in the case of an existing resource),
Input fields should be named in such a way that in the controller their values appear in the appropriate places within the params hash, and
For an existing record, when the form is initially displayed, input fields corresponding to attributes of the resource should show the current values of those attributes.
In Rails this is achieved by creating form using form_for where:
If we want to create any object we use POST method within url and PUT method if we are trying to update an existing record.
Rails framework is smart enough to use POST or PUT method by itself looking at the url of the form. So in this case we need not use method parameter within form_for url.
Probably you can start with Michael Hartl's tutorial

Not showing created blog entries

I'm fairly new to Rails and learning to create a blog using this tutorial. On step 10, once I define create and show, after creating a new post in browser I don't see any entries on show with id page. All I see is heading and and blank title and post header.
Following is my controller -
class PostController < ApplicationController
def index
end
def new
end
def create
#post = Post.new(params[:posts])
#post.save
redirect_to #post
end
def show
#post = Post.find(params[:id])
end
end
Show view ---
<h1>Show a post</h1>
<p>
<strong>Title:</strong>
<%= #post.title %>
</p>
<p>
<strong>Text:</strong>
<%= #post.text %>
</p>
Route ---
RailsBlog::Application.routes.draw do
resources :post
root :to => "post#index"
end
Form ---
<%= form_for :post, url: {action: 'create'} do |f| %>
<p>
<%= f.label :title %><br>
<%= f.text_field :title %>
</p>
<p>
<%= f.label :text %><br>
<%= f.text_area :text %>
</p>
<p>
<%= f.submit 'Submit' %>
</p>
<% end %>
May be this is just a spelling mistake, but since I've recently started learning Rails, I'm unable to resolve this.
Update: I can go to particular id using
http://localhost:3000/post/1
but am only seeing blank page with view headers
The problem is here:
#post = Post.new(params[:posts])
It should be params[:post] - singular, not plural.
Also note that the best practice with form_for is to pass an object instead of symbol:
form_for #post do |f|
Then:
You don't need to specify url
You can reuse the same form for an edit action or create action (if object creation failed due to failing validation)
This however requires to initialize new object in your new action:
def new
#post = Post.new
end
UPDATE:
Also your routes are incorrect. When defining plural resources, you need to use plural form (it's more the convention than requirement, but since you're learning stick with it). So change your routes to:
resources :posts
And rename your controller to PostsController (remember to rename file name as well). restart the server and all should work.
ANOTHER UPDATE:
You also need to rename folder app/views/post to app/view/posts.
AND YET ANOTHER UPDATE:
In rails 4, you are not allowed to mass assign any params which has not been whitelisted using strong parameters. You need to tell rails which fields you allow to be assigned first - this is a security thing. You need to make some changes to your controller:
class PostsController < ApplicationController
...
def create
#post = Post.new(post_params)
...
end
...
private
def post_params
params.require(:post).permit(:title, :text)
end
end
This is the way to tell your controller that you are expecting those attributes from your form and they can be safely assigned.
I had just similar problem on the same tutorial.
The code spelling was correct and clearly accorded to examples in tutorial and BroiSatse's answer above.
The mistake was in order of private method definition.
How it was:
...
private
def post_params
params.require(:post).permit(:title, :text)
end
def show
#post = Post.find(params[:id])
end
...
The working order:
def show
#post = Post.find(params[:id])
end
private
...
Anyway, this topic was rather helpful. Thak you for your answers!

Rails 4: Routing and sharing actions between controllers? What's the proper convention?

I'm building a Todo list in rails trying to learn how it all works. I'm having an issue with calling the action of a controller from the view of another controller.
I have a TodoList has_many TodoItem and TodoItem belongs_to TodoList.
TodoList#Model
has_many :todo_items
def has_completed_items?
todo_items.complete.size > 0
end
def has_incompleted_items?
todo_items.incomplete.size > 0
end
TodoItem#Model
belongs_to :todo_list
scope :complete, -> { where("completed_at is not null") }
scope :incomplete, -> { where(completed_at: nil) }
def completed?
!completed_at.blank?
end
Routes
resources :todo_lists do
resources :todo_items do
member do
patch :complete
end
end
end
Patch generates this route:
complete_todo_list_todo_item PATCH
/todo_lists/:todo_list_id/todo_items/:id/complete(.:format)
todo_items#complete
Now I can call this path from my TodoItem views without a problem like this: <%= link_to "Mark", complete_todo_list_todo_item_path(todo_item), method: :patch %>
After adding complete/incomplete scope to my TodoItem I added the following to my TodoList show view:
TodoList#Show
<% #todo_list.has_incompleted_items? %>
<% #todo_list.todo_items.incomplete.each do |item| %>
<li><%= item.content %></li>
<% end %>
This is properly displaying the incomplete items, so I tried to put a link to mark the item complete from within this view like this:
<% #todo_list.has_incompleted_items? %>
<% #todo_list.todo_items.incomplete.each do |item| %>
<li><%= item.content %>
<%= link_to "Mark", complete_todo_list_todo_item_path(item), method: :patch %></li>
<% end %>
Now this is where I get the following error:
NoMethodError in TodoLists#show undefined method
`complete_todo_list_todo_items_path' for #<#:0x000001071cf540>
Why is this complete#action undefined from my TodoList#show view?
What is the proper convention to share actions between controllers?
Thank you for your help.
I was able to solve this problem by removing the member block from the routes file:
resources :todo_lists do
resources :todo_items do
patch :complete
end
end
Now my action route was updated to: todo_list_todo_item_complete
So from my view I had to call the new route with it's nested resource:
link_to "Mark", todo_list_todo_item_complete_path(#todo_list, item), method: :patch
Lastly I had to update my controller to locate the proper todo_item#id in the complete block:
#todo_item = #todo_list.todo_items.find(params[:todo_item_id])

Rails 4 - Controller Edit Action Returning Wrong Record

I have a Comment model which belongs to both User and Story. Creating a comment correctly associated to the appropriate User and Story is working fine but when trying to edit the comment my edit action appears to retrieving the wrong record.
The offending action in comments_controller.rb:
def edit
#story = Story.find_by(params[:story_id])
#comment = #story.comments.find_by(params[:id])
end
The link used to render the comments/edit view:
<%= link_to 'edit', edit_story_comment_path(comment.story_id, comment.id) %>
The corresponding view:
<%= form_for(#comment, url: { controller: 'comments', action: 'update' }) do |f| %>
<%= f.text_area :content %>
<%= f.submit "update" %>
<% end %>
The edit view appears to be rendering the most recently added comment regardless of which #comment I am trying to edit.
You're using find_by, which is basically a magic find_by_X method, with no fields specified. find_by(1) generates invalid SQL for me using Postgres, but it might be that whatever database back-end your using accepts it.
Regardless, find_by certainly won't do what you want it to do.
You should be using find, if you want to find records by id:
#story = Story.find(params[:story_id])

Rails 3.1 Ajax forms don't show validation

I'm using updated pre Ruby on Rails on Ruby 1.9.2 (with rvm), and made a new test application with
$ rails generate scaffold Project name:string
and
class Project < ActiveRecord::Base
validates_presence_of :name
end
I change
<%= form_for #project do |f| %>
to
<%= form_for #project, :remote => true do |f| %>
I can now still (without any changes in the controller) add new items to the project. If I try to add with empty in the name field, it will not add anything (validates_presence_of :name stops this), but I don't get any validation error messages. I have tried the same on an application converted from 3.0 I'm working on with same results. Here I had:
class KursController < ApplicationController
# GET /kurs
# GET /kurs.xml
respond_to :js, :html
and:
def update
#kur = Kur.find(params[:id])
#kur.update_attributes(params[:kur])
flash[:notice] = "Lagret" if #kur.save
respond_with( #kur, :layout => !request.xhr? )
end
In 3.1 I get no validation error messages. Is this because of a bug in Ruby on Rails 3.1 or something I should do different?
You are missing to call these errors. Do something like this:
<%= form_for #project do |f| %>
<%= render :partial => 'my_error_messages_for', :locals => {:collection => #project} %>
In "_my_error_messages_for.html.erb":
<% if collection.errors.any? %>
<ul>
<% collection.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
<% end %>
You can create a helper for this work.
I don't believe that Ruby on Rails will automatically include the partial that you've requested. You'll need to add some JavaScript code to get it to work correctly. Something like this I imagine:
// Application.js
$("form").bind("ajax:success", function (event, data, status, xhr) {
$(event.target).replaceWith(data);
});

Resources