undefined method `has_index_path' - ruby-on-rails

I think I've tried every single "Undefined Method" question solutions on StackOverflow but still haven't found one that works for my situation...
I have a model named "Has" and I'm thinking that my problem may be related to the "s" on the end of that. I keep getting this error anytime I try to load the has/new url. /has works just fine. Just not new...
undefined method `has_index_path' for #<#:0x007ff3bbaa8d48>
Has.rb:
class Has < ActiveRecord::Base
attr_accessible :bathroom_count, :bedroom_count, :neighborhood, :price, :property_type
belongs_to :trader
end
has_controller.rb:
class HasController < ApplicationController
def index
#has = Has.all
end
def show
#has = Has.find(params[:id])
end
def new
#has = Has.new
end
def create
#has = Has.new(params[:has])
if #has.save
flash[:success] = "New Listing Created!"
redirect_to (:back)
else
redirect_to (:back)
end
end
def destroy
#has.destroy
end
end
view (new.html.erb) (using simple_form, obviously and that's working just fine on other "new" views")
<div class="center hero-unit">
<%= simple_form_for (#has) do |f| %>
<%= f.association :trader%>
<%= f.input :price %>
<%= f.input :bathroom_count %>
<%= f.input :bedroom_count %>
<%= f.input :property_type %>
<%= f.input :neighborhood %>
<%= f.button :submit %>
<% end %>
routes.rb:
Algotest::Application.routes.draw do
resources :traders
resources :wants
resources :has
root to: 'static_pages#index'
match '/add_traders', to: 'traders#new'
match '/traders', to: 'traders#index'
match '/add_has', to: 'has#new'
match '/has', to: 'has#index'
match '/add_wants', to: 'wants#new'
match '/wants', to: 'wants#index'
end
EDIT: Here's the rake routes output:
traders GET /traders(.:format) traders#index
POST /traders(.:format) traders#create
new_trader GET /traders/new(.:format) traders#new
edit_trader GET /traders/:id/edit(.:format) traders#edit
trader GET /traders/:id(.:format) traders#show
PUT /traders/:id(.:format) traders#update
DELETE /traders/:id(.:format) traders#destroy
wants GET /wants(.:format) wants#index
POST /wants(.:format) wants#create
new_want GET /wants/new(.:format) wants#new
edit_want GET /wants/:id/edit(.:format) wants#edit
want GET /wants/:id(.:format) wants#show
PUT /wants/:id(.:format) wants#update
DELETE /wants/:id(.:format) wants#destroy
has GET /has(.:format) has#index
POST /has(.:format) has#create
new_ha GET /has/new(.:format) has#new
edit_ha GET /has/:id/edit(.:format) has#edit
ha GET /has/:id(.:format) has#show
PUT /has/:id(.:format) has#update
DELETE /has/:id(.:format) has#destroy
root / static_pages#index
add_traders /add_traders(.:format) traders#new
/traders(.:format) traders#index
add_has /add_has(.:format) has#new
/has(.:format) has#index
add_wants /add_wants(.:format) wants#new
/wants(.:format) wants#index
EDIT 3
New Route after adding the Inflections code snippet. "Has" routes are looking better but now I'm getting this error on any localhost:3000 page
No route matches {:action=>"show", :controller=>"has"}
Here are the new routes:
traders GET /traders(.:format) traders#index
POST /traders(.:format) traders#create
new_trader GET /traders/new(.:format) traders#new
edit_trader GET /traders/:id/edit(.:format) traders#edit
trader GET /traders/:id(.:format) traders#show
PUT /traders/:id(.:format) traders#update
DELETE /traders/:id(.:format) traders#destroy
wants GET /wants(.:format) wants#index
POST /wants(.:format) wants#create
new_want GET /wants/new(.:format) wants#new
edit_want GET /wants/:id/edit(.:format) wants#edit
want GET /wants/:id(.:format) wants#show
PUT /wants/:id(.:format) wants#update
DELETE /wants/:id(.:format) wants#destroy
has_index GET /has(.:format) has#index
POST /has(.:format) has#create
new_has GET /has/new(.:format) has#new
edit_has GET /has/:id/edit(.:format) has#edit
has GET /has/:id(.:format) has#show
PUT /has/:id(.:format) has#update
DELETE /has/:id(.:format) has#destroy
root / static_pages#index
add_traders /add_traders(.:format) traders#new
/traders(.:format) traders#index
add_has /add_has(.:format) has#new
/has(.:format) has#index
add_wants /add_wants(.:format) wants#new
/wants(.:format) wants#index

I would suggest using a noun for the name of your resource, but if for some reason you really want to keep the current name, you could use the following hack: trick rails into thinking that the "singular" and "plural" of "has" are the same using the inflector module:
In configs/initializers/inflections.rb:
ActiveSupport::Inflector.inflections do |inflect|
inflect.irregular 'has', 'has'
end

Related

How do I create a Rails form that submits to a RESTful action?

With Rails 5, how do I create a form that submits to a RESTful action?
In my routes file I have:
resources :people do
collection do
get 'image/:id', :to => "people#image", :as => 'image'
get 'ranks', :to => "people#ranks", :as => 'ranks'
get 'search/:search(.:format)', to: 'people#search'
end
end
So I'm wondering how to construct a form that submits to the "search" action.
I tried the following:
<%= form_tag(people_search_path) do %>
<%= text_field_tag :search %>
<%= submit_tag 'Search' %>
<% end %>
But this results in the following error:
undefined local variable or method `people_search_path' for #<#<Class:0x00007ff2afc59168>:0x00007ff2afc50f68>
If you do rake routes, you'll see that your search path has no name:
image_people GET /people/image/:id(.:format) people#image
ranks_people GET /people/ranks(.:format) people#ranks
GET /people/search/:search(.:format) people#search
people GET /people(.:format) people#index
POST /people(.:format) people#create
new_person GET /people/new(.:format) people#new
edit_person GET /people/:id/edit(.:format) people#edit
person GET /people/:id(.:format) people#show
PATCH /people/:id(.:format) people#update
PUT /people/:id(.:format) people#update
DELETE /people/:id(.:format) people#destroy
If, instead, you do:
resources :people do
collection do
get 'image/:id', :to => "people#image", :as => 'image'
get 'ranks', :to => "people#ranks", :as => 'ranks'
get 'search/:search(.:format)', to: 'people#search', as: :search
end
end
You'll see your path now has a name:
image_people GET /people/image/:id(.:format) people#image
ranks_people GET /people/ranks(.:format) people#ranks
search_people GET /people/search/:search(.:format) people#search
people GET /people(.:format) people#index
POST /people(.:format) people#create
new_person GET /people/new(.:format) people#new
edit_person GET /people/:id/edit(.:format) people#edit
person GET /people/:id(.:format) people#show
PATCH /people/:id(.:format) people#update
PUT /people/:id(.:format) people#update
DELETE /people/:id(.:format) people#destroy
Which you can use as search_people_path.
BTW, I believe that (.:format) bit is unnecessary and you can simply do:
post 'search/:search', to: 'people#search', as: :search
If I were you, however, I would do:
resources :people do
collection do
get 'image/:id', :to => "people#image", :as => 'image'
get 'ranks', :to => "people#ranks", :as => 'ranks'
get :search, to: 'people#search', as: :search
end
end
Which will give you:
image_people GET /people/image/:id(.:format) people#image
ranks_people GET /people/ranks(.:format) people#ranks
search_people GET /people/search(.:format) people#search
people GET /people(.:format) people#index
POST /people(.:format) people#create
new_person GET /people/new(.:format) people#new
edit_person GET /people/:id/edit(.:format) people#edit
person GET /people/:id(.:format) people#show
PATCH /people/:id(.:format) people#update
PUT /people/:id(.:format) people#update
DELETE /people/:id(.:format) people#destroy
Then, I would update your form as Anees Muhammed suggests (I used :terms instead of :search):
<%= form_tag search_people_path, method: :get do %>
<%= text_field_tag :terms %>
<%= submit_tag 'Search' %>
<% end %>
Then, when you submit, you should get something like:
Started GET "/people/search?terms=foo" for ::1 at 2018-01-29 13:49:40 -0800
Processing by People#search as HTML
Parameters: {"utf8"=>"✓", "terms"=>"foo", "commit"=>"Search"}
And you can access your terms by doing params[:terms].
There is, BTW, nothing "non-RESTful" about this. It is, IMO, completely consistent the Guide for adding RESTful actions.
You should use search_people_path instead of people_search_path. But I don't think that change will take you to what you are trying to achieve. Since your route is get 'search/:search(.:format)', to: 'people#search' rails will expect you to provide a value for the keyword :search to build a url like /people/search/yoursearchterm with something like search_people_path(yoursearchterm). For your functionality to work, change the form to
<%= form_tag search_people_path, method: :get do %>
<%= text_field_tag :search %>
<%= submit_tag 'Search' %>
<% end %>
and then in your controller
def search
params[:search]
end
Also the routes to
get 'search', to: 'people#search'
Updated
Since you are trying to submit the form directly to a rest route like search/:search, I believe there is no direct rails way to achieve the same because that's how forms work. But if all you want is just a rest route like yourwebsite.com/search/yoursearchterm when you submit the form, there are some workarounds to achieve this. Either you have to write a piece of js on submitting the form and forward the request to your route with the input value or you can perform a redirect in the controller to the route, like this.
Routes:
resources :people do
collection do
get 'search', to: 'people#search_people'
get 'search/:search', to: 'people#search'
end
end
So, first the form will be submitted to search_people action and then redirect to search with params. In controller
def search_people
redirect_to search_people_path(params[:search])
end
This will then give you a url yoursite.com/people/search/searchterm and then in your search action, you can use the search params.
Hope this helps.

" Couldn't find User with 'id'= "

I submitted this question yesterday and was mostly able to get the issue solved from the answers I got there, however I'm now having a different but related problem.
I have this code in my show view for my object, Car:
<%= link_to #user do %>
<%= image_tag #user.profile.avatar.url, class: 'user-index-avatar' %>
<h3><%= #user.profile.company %></h3>
<% end %>
<h4><%= #user.profile.location %></h4>
<h4><%= #user.profile.phone_number %></h4>
<h4><%= #user.profile.email %></h4>
<% if user_signed_in? && #user.id == current_user.id %>
<%= link_to "Edit Listing", edit_car_path(id: #car.id ), class: 'btn btn-lg btn-warning btn-block' %>
<% end %>
When I go to this page, I get the error message "ActiveRecord::RecordNotFound in CarsController#show" and "Couldn't find User with 'id'="
Rake routes:
cars GET /cars(.:format) cars#index
GET /cars(.:format) cars#index
POST /cars(.:format) cars#create
new_car GET /cars/new(.:format) cars#new
edit_car GET /cars/:id/edit(.:format) cars#edit
car GET /cars/:id(.:format) cars#show
PATCH /cars/:id(.:format) cars#update
PUT /cars/:id(.:format) cars#update
DELETE /cars/:id(.:format) cars#destroy
new_user_profile GET /users/:user_id/profile/new(.:format) profiles#new
edit_user_profile GET /users/:user_id/profile/edit(.:format) profiles#edit
user_profile GET /users/:user_id/profile(.:format) profiles#show
PATCH /users/:user_id/profile(.:format) profiles#update
PUT /users/:user_id/profile(.:format) profiles#update
DELETE /users/:user_id/profile(.:format) profiles#destroy
POST /users/:user_id/profile(.:format) profiles#create
user_cars GET /users/:user_id/cars(.:format) cars#index
POST /users/:user_id/cars(.:format) cars#create
new_user_car GET /users/:user_id/cars/new(.:format) cars#new
GET /cars/:id/edit(.:format) cars#edit
GET /cars/:id(.:format) cars#show
PATCH /cars/:id(.:format) cars#update
PUT /cars/:id(.:format) cars#update
DELETE /cars/:id(.:format) cars#destroy
Models:
class Car < ActiveRecord::Base
belongs_to :user
end
class User < ApplicationRecord
belongs_to :plan
has_one :profile
has_many :cars
Routes.rb
get 'cars' => 'cars#index', as: :cars
resources :cars
resources :users do
resource :profile
resources :cars, shallow: true
end
CarsController:
def show
#car = Car.find( params[:id] )
#user = User.find( params[:user_id] )
#profile = #user.profile
end
The error specifies the issue is with "#user = User.find( params[:user_id] )", but I'm not sure how else to define #user. As mentioned in the linked problem above, I'm a complete newbie, so please forgive me if this is an obvious fix.
Rails find method raises this exception when it is unable to find a record by a specified id. You can double check your user_id in params and see if that id's record actually exists in database.
And by the error you have pasted, it seems user_id is null in your params.
You can always do some thing like
puts "Look for me in console\n"*10
puts params.inspect
And than see in the log window what params you are actually receiving.
I see your problem is solved in comments by accessing user association in car model, but this answer is intended to point to the root of problem and decrease number of unanswered question in SO :)

Pass value from view to Controller without querystring

I am having index method to list all students. Now I am adding search in the index with one text_field_tag. My function is working but the search value is showing as query string in the url. I don't want this.
My view code:
<p>
<%= form_tag students_path, :method => 'get' do %>
Find by name: <%= text_field_tag :search %>
<%= submit_tag "Search", :name => nil %>
<% end %>
</p>
My controller code is
def index
searchString = params[:search]
if searchString
#students = Student.where("LastName like ?", "%#{searchString}%").paginate(:page => params[:page])
else
#students = Student.paginate(:page => params[:page])
end
end
My current url look like below:
http://localhost:3000/students?utf8=%E2%9C%93&search=A
I just need like /students. Please suggest the best practice
You need to use POST request instead of GET. In order to accomplish that, change your form_tag from:
<%= form_tag students_path, :method => 'get' do %>
to
<%= form_tag students_path, :method => 'post' do %>
What could possibly go wrong...
As #carlosramireziii mentioned, answering this question, requires a bit more work (and he is absolutely right!), so - there is update
1. Custom routes
If you are configuring your routes on your own, one of ways proceeding with this is to add a route, that will properly accept your requests. Take a look at config/routes.rb:
Rails.application.routes.draw do
match '/students', controller: :students, action: :index, via: [:get, :post]
# other definitions
end
Definition like this will create following route for you:
students GET|POST /students(.:format) students#index
This will make your new POST request nicely fall into students#index, generating expected result. However, if you are defining your routes via resources it's not that easy change. This leads us to...
2. Modifying standard resources routes
If routes for students are defined as follows:
Rails.application.routes.draw do
resources :students
# other definitions
end
the following routes are registered:
students GET /students(.:format) students#index
POST /students(.:format) students#create
new_student GET /students/new(.:format) students#new
edit_student GET /students/:id/edit(.:format) students#edit
student GET /students/:id(.:format) students#show
PATCH /students/:id(.:format) students#update
PUT /students/:id(.:format) students#update
DELETE /students/:id(.:format) students#destroy
This indicates, the POST request falls into students#create. In order to make it work, you need to change the create action, to something like:
class StudentsController < ApplicationController
# code omitted
def create
if params.include?('search')
#students = Student.where("LastName like ?", "%#{searchString}%").paginate(:page => params[:page])
render :index
else
# your current code from create action
end
end
end
While this will work, it is not recommended to do it this way. The create action does two things now, which is considered a bad pattern (or bad smell at least), and it is error prone.
So, what can we do?
Making search the right way
1. Custom search route
Define custom collection route:
Rails.application.routes.draw do
resources :students do
collection do
post :search
end
end
# other definitions
end
This registers following routes:
search_students POST /students/search(.:format) students#search
students GET /students(.:format) students#index
POST /students(.:format) students#create
new_student GET /students/new(.:format) students#new
edit_student GET /students/:id/edit(.:format) students#edit
student GET /students/:id(.:format) students#show
PATCH /students/:id(.:format) students#update
PUT /students/:id(.:format) students#update
DELETE /students/:id(.:format) students#destroy
You need to change your form_tag as follows:
<%= form_tag search_students_path, :method => 'post' do %>
And add search action to StudentsController:
class StudentsController < ApplicationController
# code omitted
def search
#students = Student.where("LastName like ?", "%#{searchString}%").paginate(:page => params[:page])
# If you don't want to create separate template for `search`,
# you can try to reuse your `index` template with
# render :index
end
end
2. Use students#index with params passed in URL
This approach is more REST-y, and it makes it available to pass the whole URL to someone else, so the another person is able to see exactly the same result of filtering, which is impossible with params "hidden" in POST request.
I hope I've covered all possibilities. If you have any questions - I'm more than happy to answer!
Good luck!

Rails friendship canceling, decline

I am trying to build a friendship system sorta following this link: How to Implement a Friendship Model in Rails 3 for a Social Networking Application?. However lack a bit. I was able to create a relationship however i am not to sure on how to perform the following actions: cancel, decline, accept.
So lets say i try to cancel the relationship i do the following on the pending, to call the actions i do the follow:
<% #customer.pending_friends.each do |pf| %>
<%= link_to pf.incomplete_name, cancel_friendships_path(:friend_id => pf), :method => :post %><br />
<% end %>
Here the controller of cancel
def cancel
#customer = current_customer
#friend = Customer.find(params[:friend_id])
if #customer.pending_friends.include?(#friend)
Friendship.breakup(#customer, #friend)
flash[:notice] = "Friendship Canceled"
else
flash[:notice] = "No Friendship request"
end
redirect_to root_url
end
and here my breakup function
# Delete a friendship or cancel a pending request.
def self.breakup(customer, friend)
transaction do
destroy(find_by_customer_id_and_friend_id(customer, friend))
destroy(find_by_customer_id_and_friend_id(friend, customer))
end
end
I am however getting a no route errors when clicking on the cancel links. What i am doing wrong??
Here on the request
route.rb
resources :friendships do
collection do
get 'cancel'
get 'decline'
end
end
resources :friendships
rake routes
cancel_friendships GET /friendships/cancel(.:format) friendships#cancel
decline_friendships GET /friendships/decline(.:format) friendships#decline
GET /friendships(.:format) friendships#index
POST /friendships(.:format) friendships#create
GET /friendships/new(.:format) friendships#new
GET /friendships/:id/edit(.:format) friendships#edit
GET /friendships/:id(.:format) friendships#show
PUT /friendships/:id(.:format) friendships#update
DELETE /friendships/:id(.:format) friendships#destroy
/********************************************************/
friendships GET /friendships(.:format) friendships#index
POST /friendships(.:format) friendships#create
new_friendship GET /friendships/new(.:format) friendships#new
edit_friendship GET /friendships/:id/edit(.:format) friendships#edit
friendship GET /friendships/:id(.:format) friendships#show
PUT /friendships/:id(.:format) friendships#update
DELETE /friendships/:id(.:format) friendships#destroy
The problem is that in your routes you have:
get 'cancel'
but your cancel-link is doing a post request, not a get:
<%= link_to ..., ..., :method => :post %>
Personally I think it should be a delete request.
In your routes:
delete 'cancel'
In your view:
<%= link_to pf.incomplete_name, cancel_friendships_path(:friend_id => pf), :method => :delete %>
Your code may have other problems, but this is one thing you have to fix.

How do I render a partial for a view of a nested resource? - Rails 3.1

This is my route:
scope ":username" do
resources :feedbacks
end
I am on my home/index.html.erb view and I am trying to do this:
<%= render "feedbacks/form" %>
But this gives me this error:
ActionView::Template::Error (No route matches {:controller=>"feedbacks", :format=>nil}):
1: <%= form_for(#feedback) do |f| %>
2: <% if #feedback.errors.any? %>
3: <div id="error_explanation">
4: <h2><%= pluralize(#feedback.errors.count, "error") %> prohibited this feedback from being saved:</h2>
app/views/feedbacks/_form.html.erb:1:in `_app_views_feedbacks__form_html_erb__3181571289116259961_2487495480'
app/views/home/index.html.erb:18:in `_app_views_home_index_html_erb___397233383548615486_2487321620'
This is my rake routes for feedbacks:
feedbacks GET /:username/feedbacks(.:format) {:action=>"index", :controller=>"feedbacks"}
POST /:username/feedbacks(.:format) {:action=>"create", :controller=>"feedbacks"}
new_feedback GET /:username/feedbacks/new(.:format) {:action=>"new", :controller=>"feedbacks"}
edit_feedback GET /:username/feedbacks/:id/edit(.:format) {:action=>"edit", :controller=>"feedbacks"}
feedback GET /:username/feedbacks/:id(.:format) {:action=>"show", :controller=>"feedbacks"}
PUT /:username/feedbacks/:id(.:format) {:action=>"update", :controller=>"feedbacks"}
DELETE /:username/feedbacks/:id(.:format) {:action=>"destroy", :controller=>"feedbacks"}
Edit 1
When I pass in the local instance variable #feedback like this: <%= render "feedbacks/form", :local => #feedback %> which is pulling from my home controller, where it is declared like this:
class HomeController < ApplicationController
def index
#users = User.all
#feedback = Feedback.new
end
end
I still get this error:
Routing Error
No route matches {:controller=>"feedbacks", :format=>nil}
Edit 2
I also have a users resource specified in my routes file, that looks like this:
resources :users
scope ":username" do
resources :feedbacks
end
Seems like form_for can't find the correct route, this line suggests you don't have an instance variable #feedback set when trying to render that partial:
(No route matches {:controller=>"feedbacks", :format=>nil})
Notice there is no :id parameter in that hash (which is likely being passed to the router to generate the correct URL to submit the form to).
Do you define a #feedback somewhere in the controller action (preferable) or views you're using? If you think you are, try the following above line 1 of your partial:
logger.info "feedback object: #{#feedback.inspect}"
Edit:
First of all, locals should be passed not as :local => #feedback but as:
:locals => {:variable_name_in_partial => value_for_variable_name}
Second of all, you are trying to access #feedback which is an instance variable accessible to views even if it's not passed explicitly (as long as it's set). So as long as you set it in the HomeController#index method you don't need to pass it to any views locally.
Also, you are not using the correct syntax for rendering partials (wish I had noticed earlier!).
Change the following:
<%= render "feedbacks/form" %>
To this:
<%= render :partial => "feedbacks/form" %>
Aren't you forgetting to pass in :username? Your route says scope :username
If I add a route like yours, open up the Rails console, include Rails.application.routes.url_helpers and run feedbacks_path, I get a routing error, but feedbacks_path :username => 'bob' works fine.
> feedbacks_path(:username => 'bob')
=> "/bob/feedbacks"
Are you sure you want scope? What about a nested resource as per:
resources :users do
resources :feedbacks
end
Also, I've had trouble when using controllers with plural names. You might try renaming FeedbacksController to FeedbackController.

Resources