I have a controller "find_numbers", which I'm using to submit a form to the Twilio API. Before it submits though, I'd like to validate against two form fields, which aren't in the data model for this controller. The fields are :name, and :original_number
So, in my find_numbers model, I added attr_accessor :name, attr_accessor :originial number to run a validates command under it.
After doing that and submitting the form as invalid, I get the error :
Routing Error
No route matches {:controller=>"phone", :action=>"new"}
Try running rake routes for more information on available routes.
I'm not sure why it says there's no roots, but I'm not sure why it's accessing that anyways. I want it to POST to find_numbers
The find_numbers/new template
<%= form_tag("/find_numbers", :method => "post", :id => "new_user" ) do %>
<%= render 'shared/error_messages' %>
<%= label_tag(:name, "What Are You Tracking?") %>
<%= text_field_tag(:name) %>
<%= label_tag(:original_number, "Your Orginal Number") %>
<%= text_field_tag(:original_number) %>
<%= label_tag(:in_postal_code, "Near US postal code (e.g. 94117):") %>
<%= text_field_tag(:in_postal_code) %>
<%= label_tag(:near_number, "Near this other number (e.g. +4156562345)") %>
<%= text_field_tag(:near_number) %>
<%= label_tag(:contains, "Matching this pattern (e.g. 415***EPIC):") %>
<%= text_field_tag(:contains) %>
<%= submit_tag("Search", :class => "btn btn-large btn-primary") %>
<% end %>
here's my find_number model
class FindNumber < ActiveRecord::Base
attr_accessor :name
attr_accessor :original_number
validates :name, presence: true
validates :original_number, presence: true
end
Here's my Find_number controller
class FindNumbersController < ApplicationController
def new
#user = current_user
end
def create
#user = current_user
client = Twilio::REST::Client.new(#user.twilio_account_sid, #user.twilio_auth_token)
search_params = {}
%w[in_postal_code near_number contains].each do |p|
search_params[p] = params[p] unless params[p].nil? || params[p].empty?
end
local_numbers = client.account.available_phone_numbers.get('US').local
#numbers = local_numbers.list(search_params)
unless #numbers.empty?
render 'find_numbers/show'
else
flash.now[:error] = "Sorry, We Couldn't Find Any Numbers That Matched Your Search! Maybe Something Simpler?"
render 'find_numbers/new'
end
end
def show
end
end
Any thoughts on accomplishing this would be greatly appreciated!
Edit
Routes.rb file
Dct::Application.routes.draw do
resources :users
resources :sessions, only: [:new, :create, :destroy]
resources :phones, only: [:new, :create, :destroy]
resources :find_numbers, only: [:new, :create, :destroy]
match '/find_numbers', to: 'find_numbers#new'
match '/signup', to: 'users#new'
match '/login', to: 'sessions#new'
match '/signout', to: 'sessions#destroy', via: :delete
root to: 'static_pages#home'
match '/product_demo', to: 'static_pages#product_demo'
match '/pricing', to: 'plans#index'
match '/contact', to: 'static_pages#contact'
Edit
Here is the server log, of what happened when I hit submit
http://stepanp.com/railserror.jpg
Also, here's the find_numbers/show view
From what you've posted, the only other thing that looks suspicious to me is that you presumably have a PhonesController (plural) since you've declared resources :phones, but the routing error seems to occur because it is looking for a PhoneController (singular).
Related
I have created a ToDoList based off Hartl's tutorial, and following a video and worded tutorial to add a tagging system. I have followed till Section 10, where they asked me to modify my new.html.erb file to the code as shown on the source. To improvise for structural differences in code, I would edit some other files, like in this case, my micropost_form partial instead. Occasionally, I alternated between the code in the video and code in the worded tutorial because some of them would produce error messages or would not produce the required functionality. Here are the files that I think are involved in this question.
_micropost_form.html.erb(The filling up form that would be displayed on the user's home page)
<%= simple_form_for #micropost do |f| %>
<%= render 'shared/error_messages', object: f.object %>
<div class="field">
<%= f.label :content %><br />
<%= f.text_area :content, placeholder: "Add new task..." %>
</div>
<div class="field">
<%= f.label :tag_list, "Tags (separated by commas)" %><br />
<%= f.text_field :tag_list %>
</div>
<%= f.submit "Add Task", class: "btn btn-primary" %>
<% end %>
micropost.html.erb(for showing the individual micro posts)
<li id="micropost-<%= micropost.id %>">
<%= link_to gravatar_for(micropost.user, size: 50), micropost.user %>
<span class="user"><%= link_to micropost.user.name, user_path(micropost.user) %></span>
<span class="content"><%= micropost.content %></span>
<p><small>Tags: <%= raw micropost.tags.map(&:name).map { |t| link_to t, tag_path(t) }.join(', ') %></small</p>
<span class="timestamp">
Posted <%= time_ago_in_words(micropost.created_at) %> ago.
<% if current_user?(micropost.user) %>
<%= link_to "Done", micropost_path(micropost), method: :delete, data: { confirm: "Keep up the good work!" } %>
<% end %>
</span>
</li>
routes.rb
Rails.application.routes.draw do
resources :users
resources :microposts
get '/about', to: 'static_pages#about'
get '/contact', to: 'static_pages#contact'
get '/signup', to: 'users#new'
post '/signup', to: 'users#create'
get '/login', to: 'sessions#new'
post '/login', to: 'sessions#create'
delete '/logout', to: 'sessions#destroy'
get '/users/admin', to: 'users#admin'
get 'tags/:tag', to: 'microposts#index', as: :tag
root 'static_pages#home'
end
micropost_controller
class MicropostsController < ApplicationController
before_action :logged_in_user, only: [:create, :destroy]
before_action :correct_user, only: :destroy
def index
params[:tag] ? #microposts = Micropost.tagged_with(params[:tag]) : #microposts = Micropost.all
end
def show
#micropost = Micropost.find(params[:id])
end
def create
#micropost = current_user.microposts.build(micropost_params)
if #micropost.save
flash[:success] = "Micropost created!"
redirect_to root_url
else
#feed_items = []
render 'static_pages/home'
end
end
def destroy
#micropost.destroy
flash[:success] = "You have deleted a task!"
redirect_to request.referrer || root_url
end
private
def micropost_params
params.require(:micropost).permit(:content, :tag_list, :tag,
{tag_ids: [] }, :tag_ids)
end
def correct_user
#micropost = current_user.microposts.find_by(id: params[:id])
redirect_to root_url if #micropost.nil?
end
end
Micropost model
class Micropost < ApplicationRecord
belongs_to :user
has_many :taggings
has_many :tags, through: :taggings
default_scope -> { order(created_at: :desc) }
validates :user_id, presence: true
validates :content, presence: true, length: {maximum: 140 }
attr_accessor :tag_list
def self.tagged_with(name)
Tag.find_by!(name: name).microposts
end
def self.tag_counts
Tag.select('tags.*, count(taggings.tag_id) as count')
.joins(:taggings).group('taggings.tag_id')
end
def tag_list
tags.map(&:name).join(', ')
end
def tag_list=(names)
self.tags = names.split(',').map do |n|
Tag.where(name: n.strip).first_or_create!
end
end
end
Tag model
class Tag < ApplicationRecord
attr_accessor :name
has_many :taggings
has_many :microposts, through: :taggings
end
static_pages controller
class StaticPagesController < ApplicationController
def home
if logged_in?
#micropost = current_user.microposts.build
#feed_items = current_user.feed.paginate(page: params[:page])
end
end
def help
end
def about
end
def contact
end
end
feed.html.erb
<% if #feed_items.any? %>
<ol class="microposts">
<%= render #feed_items %>
</ol>
<%= will_paginate #feed_items %>
<% end %>
I got the following error
ActionController::UrlGenerationError in StaticPages#home
No route matches {:action=>"index", :controller=>"microposts", :tag=>nil}, missing required keys: [:tag]
app/views/microposts/_micropost.html.erb:5:in `block in _app_views_microposts__micropost_html_erb___3891111682689684005_70324923859580'
app/views/microposts/_micropost.html.erb:5:in `map'
app/views/microposts/_micropost.html.erb:5:in `_app_views_microposts__micropost_html_erb___3891111682689684005_70324923859580'
app/views/shared/_feed.html.erb:3:in `_app_views_shared__feed_html_erb__3168328449514417483_70324923896060'
app/views/static_pages/home.html.erb:13:in `_app_views_static_pages_home_html_erb__3511776991923566869_70324898321240'
Can anyone suggest what might be wrong here? Please let me know if more information is needed.
Update: I have implemented some of the changes provided by the answer below, but still has not understood why :tag is not detected, and why the code in red is actually highlighted.
ActionController::UrlGenerationError in StaticPages#home
No route matches {:action=>"index", :controller=>"microposts", :tag=>nil}, missing required keys: [:tag]
The problem is you don't have an index route for your microposts.
Rails.application.routes.draw do
root 'static_pages#home'
get '/readme', to: 'static_pages#readme'
get '/about', to: 'static_pages#about'
get '/contact', to: 'static_pages#contact'
get '/signup', to: 'users#new'
post '/signup', to: 'users#create'
get '/login', to: 'sessions#new'
post '/login', to: 'sessions#create'
delete '/logout', to: 'sessions#destroy'
get '/users/admin', to: 'users#admin'
resources :users
resources :microposts, only: [:create, :destroy] #Here's the problem
get 'tags/:tag', to: 'microposts#index', as: :tag
end
change to:
resources :microposts, only: [:index, :create, :destroy]
EDIT:
Another problem is
if logged_in?
#micropost = current_user.microposts.build #this just returns a new 1
#feed_items = current_user.feed.paginate(page: params[:page])
end
You probably want something like:
if logged_in?
#microposts = current_user.microposts
#feed_items = Micropost.all.paginate(page: params[:page])
end
This will give you all the user's microposts. Then you iterate through them in your views.
I actually found the cause of the problem to be quite simple. After running rails console, it seems like my db:seed wasn't even raked properly, causing my tags to have nil names and causing me to be unable to find the route. Looking further into Rails console is adding nil instead of values to solve my seed adding problem, I realised I have added attr_accessor, forgetting that normal attributes should be added via the command line into the Migration instead of writing into the Model directly. Removing it according to the post updates my database and the code works.
UPDATE - I'VE NOW SOLVED THIS PROBLEM - I created a partial for the each Course item and rendered them from the main listing view. Thanks for all your help, I'm not really sure why it worked but it did END OF UPDATE
Apologies if this looks like a repeat posting but I've tried applying solutions to similar questions and they haven't worked, I'm stuck! Any suggestions welcomed, thank you.
Problem
I have a 'Courses' model which belongs to a 'Listings' model. The courses are created and deleted on a page belonging to Listing i.e. "/listing/2/courses"
Error Message
No route matches [DELETE] "/listings/2/courses"
Courses Controller def destroy detail
class CoursesController < ApplicationController
before_action :authenticate_user!, except: [:show]
before_action :set_listing
before_action :set_course, except: [:index, :new, :create]
def destroy
#course = #listing.courses.find(params[:id])
#course.destroy
flash[:notice] = "Course deleted!"
redirect_back(fallback_location: request.referer)
end
private
def set_course
#listing = Listing.find(params[:listing_id])
#course = Course.find(params[:id])
end
def set_listing
#listing = Listing.find(params[:listing_id])
end
def course_params
params.require(:course).permit(:name, :curriculum_type, :summary, :address, :course_places, :start_date, :finish_date, :price)
end
end
listing/listingID/courses page detail
<%= #listing.courses.each do |f| %>
<div class="jumbotron">
<ul>
<li>Name = <%= f.name %></li>
<li>Type of course = <%= f.curriculum_type %></li>
<li>Number of places = <%= f.course_places %></li>
<li>Start Date = <%= f.start_date %></li>
<li>Finish Date = <%= f.finish_date %></li>
<li>Price (£) = <%= f.price %></li>
<%= link_to "Delete Course", listing_courses_path(#listing, #course), method: :delete %>
</ul>
</div>
<% end %>
Routes.rb detail
resources :users, only: [:show]
resources :listings, except: [:edit] do
member do
get 'listing'
get 'pricing'
get 'description'
get 'photo_upload'
get 'amenities'
get 'location'
get 'courses'
end
resources :courses, except: [:edit] do
member do
get 'listing'
get 'pricing'
get 'description'
get 'photo_upload'
get 'amenities'
get 'location'
end
end
end
<%= link_to listing_course_path(#listing,f), :method => :delete, :data => { :confirm => 'Are you sure?' } %>
or try
<%= link_to listing_course_path(#listing,id: f.try(:id)), :method => :delete, :data => { :confirm => 'Are you sure?' } %>
route.rb
resources :listings do
resources :courses
end
By default, destroy method expects an ID as it's a member route. You are using listing/listingID/courses route without an ID. For that you need to define listing and/or courses as singular resources (read this) like:
resource :courses do
:
end
as described in this answer or make destroy a collection route like so:
resources :courses, except: [:edit] do
delete :destroy, on: :collection
:
rest...
end
Try and see if this works.
By the way, this looks a bit redundant as you are iterating over each #listing.courses and calling courses#destroy where you are destroying all the courses of #listing anyhow. So, why do #listing.courses.each in the first place. You should have either used a listing#destroy_courses method or remove #listing.courses.each iteration.
Update path in link_to to listing_course_path(#listing, #course) from listing_courses_path(#listing, #course)
<%= link_to "Delete Course", listing_course_path(#listing, f), method: :delete %>
All of the sudden I am getting this error even though it has been working for a while:
No route matches [POST] “/stories/id/invites”
Routes:
story_invites_path GET /stories/:story_id/invites(.:format) invites#index
routes.rb
resources :stories do
match '/stories/:id/invite', to: 'invite#show', via: 'get'
resources :invites , only: [:index, :show, :destroy ]
end
invites/index view
<%= form_for #invite , :url => story_invites_path do |f2| %>
<%= f2.text_field :user_id, :value => user.id , :class => 'number_field' %>
<%= f2.submit 'Send', class: 'btn btn-primary' %>
<% end %>
invites controller
def create
#invite = #story.invites.new(invite_params)
if #invite.save
flash[:success] = 'The user was invited!'
redirect_to(:back)
else
render :new
end
end
How do I add a post method to my invites path?
You have all sort of icky things...
This:
resources :stories do
match '/stories/:id/invite', to: 'invite#show', via: 'get'
resources :invites , only: [:index, :show, :destroy ]
end
Should be:
resources :stories do
resources :invites
end
Which will give you:
story_invites GET /stories/:story_id/invites(.:format) invites#index
POST /stories/:story_id/invites(.:format) invites#create
new_story_invite GET /stories/:story_id/invites/new(.:format) invites#new
edit_story_invite GET /stories/:story_id/invites/:id/edit(.:format) invites#edit
story_invite GET /stories/:story_id/invites/:id(.:format) invites#show
PATCH /stories/:story_id/invites/:id(.:format) invites#update
PUT /stories/:story_id/invites/:id(.:format) invites#update
DELETE /stories/:story_id/invites/:id(.:format) invites#destroy
stories GET /stories(.:format) stories#index
POST /stories(.:format) stories#create
new_story GET /stories/new(.:format) stories#new
edit_story GET /stories/:id/edit(.:format) stories#edit
story GET /stories/:id(.:format) stories#show
PATCH /stories/:id(.:format) stories#update
PUT /stories/:id(.:format) stories#update
DELETE /stories/:id(.:format) stories#destroy
If you really want to limit your invite routes, fine. But right now, you're limiting out create. Which is really why you're getting:
No route matches [POST] “/stories/id/invites”
Because you TOLD rails you didn't want a create path. Rails is dumb that way. Does what you tell it. Not what you mean.
Also, this:
match '/stories/:id/invite', to: 'invite#show', via: 'get'
Is just really full of badness and banana slugs. Please don't do that. To yourself. Or to us.
This:
<%= form_for #invite , :url => story_invites_path do |f2| %>
<%= f2.text_field :user_id, :value => user.id , :class => 'number_field' %>
<%= f2.submit 'Send', class: 'btn btn-primary' %>
<% end %>
probably needs to look more like this:
<%= form_for :invite, story_invites_path(story) do |f2| %>
<%= f2.hidden_field :invite, :user_id, value: #user.id %>
<%= f2.submit 'Send', class: 'btn btn-primary' %>
<% end %>
Use :invite instead of #invite because you're in index and you probably don't have an #invite. If you do, fine. But rails can use the symbol to infer the correct fields.
You're going to have to look up that hidden_field method, because I'm doing this from memory.
And I don't know where you're going to get story from because you're in your index method. But, you can do something like #stories = Story.all. In which case this whole block will need to wrapped in something like:
<% #stories.each do |story| %>
<%= story.name %>
<%= form_for :invite, story_invites_path(story) do |f2| %>
<%= f2.hidden_field :invite, :user_id, value: #user.id %>
<%= f2.submit 'Send', class: 'btn btn-primary' %>
<% end %>
<% end %>
Man, this makes me remember why I dislike erb. If you were doing this in HAML, it would be pretty, like unicorns and rainbows:
- #stories.each do |story|
.story-container{id: "story-id-#{story.id}"}
.story-name
= story.name
.story-invite-container
= form_for :invite, story_invites_path(story) do |f2|
= f2.hidden_field :invite, :user_id, value: #user.id
= f2.submit 'Send', class: 'btn btn-primary'
Don't you like unicorns and rainbows? Look at all those beautiful divs with ids and classes just waiting to be dressed up with your butt-kicking, mad-ninja-skills CSS (display: inline-block, anyone?). (Please tell me you're using SASS. Please?)
Now, on submit, your params are going to look something like (I'm making up the story_id and 'user_id` values):
{..., story_id: 4, invite: {user_id: 1}, ...}
I assume in invites_controller, you have something like:
class InvitesController < ActionController::Base
def index
...
#stories = Story.all
...
end
def create
#story = Story.find_by(id: params[:story_id])
#invite = #story.invites.new(invite_params)
if #invite.save
flash[:success] = 'The user was invited!'
redirect_to(:back)
else
render :new
end
end
def invite_params
params.require(:invite).permit(:user_id)
end
end
And that all ought to hang together.
For the life of me, I don't know why you redirect_to :new, but hey whatever floats your boat. (Are sure you don't want to redirect_to stories_path or maybe redirect_to story_path?)
Update your routes.rb to include create in your resources :invites, like this:
resources :stories do
match '/stories/:id/invite', to: 'invite#show', via: 'get'
resources :invites , only: [:index, :show, :destroy, :create ]
end
That change will generate this new route:
story_invites POST /stories/:story_id/invites(.:format) invites#create
I am using a form for "GET" method. I created a text field (in testing.html.erb) for user to enter the name. I want the name to be passed into the controller and based on the name, I want to retrieve his data from the database through a query.
The problem here is that I am not getting anything into the instance variable in the controller action (Nothing is printed on screen when I display #testing in "testing.html.erb"). Below is my routes.rb file.
Rails.application.routes.draw do
resources :users
# The priority is based upon order of creation: first created -> highest priority.
# See how all your routes lay out with "rake routes".
# You can have the root of your site routed with "root"
# root 'welcome#index'
# Example of regular route:
get 'index' => 'users#index'
get 'testing' => 'users#testing'
# Example of named route that can be invoked with purchase_url(id: product.id)
# get 'products/:id/purchase' => 'catalog#purchase', as: :purchase
.....
This is my testing.html.erb file
<h1> Testing page </h1>
<%= form_for users_path, :url => {:action => "testing", :name => :name}, :html => {:method => :get} do |f| %>
<%= f.label :first_name %><br />
<%= f.text_field :name %><br />
<%= f.submit "View Schedule" %>
<% end %>
<%= #testing %>
<%#= #testing.email %>
<%#= #testing.content %>
Please note that I commented #testing.email/content in above file to supress the error (undefined method `email' for nil:NilClass).
Below is my users_controller.rb file.
class UsersController < ApplicationController
before_action :set_user, only: [:show, :edit, :update, :destroy]
#before_action :user_set, only: [:testing]
# GET /users
# GET /users.json
def index
#users = User.all
#test = params[:name]
#test_index = params[:age]
end
# GET /users/1
# GET /users/1.json
def show
end
def testing
#testing = User.find_by(name: params[:name])
#if #testing.name == "Siri"
# #render text: "Hello #{#testing.name}"
#redirect_to action: :index
#end
end
.........
private
# Use callbacks to share common setup or constraints between actions.
def set_user
#user = User.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def user_params
params.require(:user).permit(:name, :email, :content)
end
end
The log-file shows the following.
Processing by UsersController#testing as HTML
Parameters: {"utf8"=>"✓", "/users"=>{"name"=>"hello rails"}, "commit"=>"View Schedule"}
I also tried to use strong params as User.find_by(name: params[:users][:name]) which throws error "undefined method `[]' for nil:NilClass".
I think I am going wrong somewhere. Please correct me. Thank you for your time.
Issue lies here:
Parameters: {"utf8"=>"✓", "/users"=>{"name"=>"hello rails"}, "commit"=>"View Schedule"}
Do you see /users key in your params? It shoudn't be there. This indicates problem with your form:
<%= form_for users_path, :url => {:action => "testing", :name => :name}, :html => {:method => :get} do |f| %>
First argument is expected to be a string (which is then used as a name of form params) or ActiveModel object. In your case, it is string returned by users_path, which is just '/users'. It should be #testing
<%= form_for #testing, :url => {:action => "testing", :name => :name}, :html => {:method => :get} do |f| %>
That will fix your current issue, you will get another shortly after that, which should go into a separate question.
You'll be best using the following:
#app/views/users/testing.html.erb
<%= #user.try(:name) %>
<%= form_tag users_testing_path, method: :get do |f| %>
<%= f.text_field :name %>
<%= f.submit "View Schedule" %>
<% end %>
This will allow:
#app/controllers/users_controller.rb
class UsersController < ApplicationController
def testing
#user = User.find_by name: params[:name]
end
end
You could improve your routes file too:
#config/routes.rb
resources :users, path: "", only: :index, path_names: { index: "index" } do #-> url.com/index
get :testing, on: :collection #-> url.com/testing
end
I am having a lot of trouble trying to pass an id from a model into a different controller. I've read similar posts and tried different solutions, but can't seem to pass the Event id into the Invitations controller.
UPDATE
The goal is that a user, while looking at an event they created, will click on an Invite link. This link needs to save the ID from the Event it came from so that Invitations can be associated with that event.
In my models, I for the Event model, I have 'has_many "invitations' and for the Invitation model I have 'belongs_to :events'
Here is my code.
show.html.erb within my Events folder:
<%= link_to 'Invite guests', invitations_path(:event => #event.id) %>
This link maps to 'invitations#new':
<% provide(:title, 'Invite Guests') %>
<h1>Invite your guests</h1>
<%= form_for(#invitation) do |f| %>
<%= render 'shared/error_messages', object: f.object %>
<%= f.label :name %>
<%= f.text_field :name, :placeholder => "Name" %> <br>
<%= f.label :email %>
<%= f.text_field :email, :placeholder => "Email" %> <br>
<%= f.submit "Send" %>
InvitationsController:
def index
end
def new
#invitation = Invitation.new
end
def create
user = current_user.events.find(params[:event])
#invitation = user.invitations.build(params[:invitation])
if #invitation.save
flash[:success] = "Invitations sent!"
redirect_to user
else
render '/home'
end
end
I know that if I replace:
user = current_user.events.find(params[:event])
with:
user = current_user.events.find(1)
Routes:
resources :users
resources :sessions, only: [:new, :create, :destroy]
resources :events, only: [:show, :create, :destroy]
resources :invitations, only: [:new, :create]
root to: '/home'
match '/signup', to: 'users#new'
match '/signin', to: 'sessions#new'
match '/signout', to: 'sessions#destroy', via: :delete
match '/events', to: 'events#new'
match '/invitations', to: 'invitations#new'
Everything works fine, but of course, this is not suitable since I am hard coding the Event ID. I am pretty new to RoR (about 2 months of experience) so there may be a more efficient way to do this. So any help would be much appreciated.
<%= link_to 'Invite guests', invitations_path(:event => #event.id) %>
Goes to:
def index
Not to:
def create
If you want to go to create do:
<%= link_to 'Invite guests', invitations_path(:event => #event.id), method: :post %>