I'm having a problem with a nested routing when I try to edit the subresource (lessons) from it's show page by clicking the edit link as described below. There are two classes involved: Units and Lessons. I can't understand why Rails is trying to route to course controller (a parent of Units).
Any help would be greatly appreciated.
I am getting this error and url
http://localhost:3000/units/3/lessons/13/edit
Routing Error
No route matches {:action=>"show", :controller=>"courses", :id=>nil}
config/routes.rb
resources :courses do
resources :units
end
resources :units do
resources :lessons
end
** from rake routes**
unit_lessons GET /units/:unit_id/lessons(.:format) lessons#index
POST /units/:unit_id/lessons(.:format) lessons#create
new_unit_lesson GET /units/:unit_id/lessons/new(.:format) lessons#new
edit_unit_lesson GET /units/:unit_id/lessons/:id/edit(.:format) lessons#edit
unit_lesson GET /units/:unit_id/lessons/:id(.:format) lessons#show
code for clicked link
<%= link_to "Edit Lesson", edit_unit_lesson_path(#unit, #lesson ) %>
LessonsController
class LessonsController < ApplicationController
before_filter :find_unit
before_filter :find_lesson, :only => [:show,:edit,:update,:destroy]
.
.
.
private
def find_unit
#unit = Unit.find(params[:unit_id])
end
def find_lesson
#lesson = #unit.lessons.find(params[:id])
end
Server Log File
Started GET "/units/3/lessons/12/edit" for 127.0.0.1 at 2012-08-02 14:50:55 +0200
Processing by LessonsController#edit as HTML
Parameters: {"unit_id"=>"3", "id"=>"12"}
Unit Load (0.1ms) SELECT "units".* FROM "units" WHERE "units"."id" = ? LIMIT 1 [["id", "3"]]
Lesson Load (0.1ms) SELECT "lessons".* FROM "lessons" WHERE "lessons"."unit_id" = 3 AND "lessons"."id" = ? LIMIT 1 [["id", "12"]]
Rendered lessons/_form.html.erb (3.4ms)
Rendered lessons/edit.html.erb within layouts/application (4.4ms)
Completed 500 Internal Server Error in 7ms
ActionController::RoutingError (No route matches {:action=>"show", :controller=>"courses", :id=>nil}):
app/views/lessons/edit.html.erb:8:in `_app_views_lessons_edit_html_erb___3830769233446763788_70188197130200'
Found it. The link was part of a table body, built with an .each iterator. I needed to change the name from "#lesson" to "lesson" as that is what is referenced when the table is built.
For anyone else stuck on a similar problem, I've put the functioning code below.
<tbody>
<% #unit.lessons.each do |lesson| %>
<tr>
<td><%= link_to lesson.lesson_name, [#unit, lesson] %></td>
.
.
.
<td><%= link_to 'Edit', edit_unit_lesson_path(#unit, lesson ) %></td>
</tr>
<% end %>
</tbody>
Related
This probably is a nooby one. I'm building a search form.
In the model document.rb, I have this :
pg_search_scope :search_full_text,
:against => :full_text,
:using => {
:tsearch => {
:prefix => true
}
}
and in documents_controller.rb, I have :
def find
$results = Document.search_full_text(params[:ch_acte][:text])
end
But NOTHING gets send to the database. The server log only says:
Started POST "/documents/find" for ::1 at 2017-01-19 08:48:07 +0100
Processing by DocumentsController#find as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"ZkqVYMuqMqnUjLer/FVdBdtv4cycp71dXqPQw6j0mfHKX5ptin7p7YiYFj8bNtjciQDmHzbKtBnZoILpGGvl8Q==", "ch_acte"=>{"text"=>"complet", "words"=>"", #[cut for brievity]}, "commit"=>"Cherche"}
Rendering documents/find.html.erb within layouts/messources
Rendered documents/find.html.erb within layouts/messources (0.4ms)
Completed 200 OK in 216ms (Views: 210.2ms | ActiveRecord: 0.0ms)
Other than the method pg_search_scope in the model and calling that method in the controller, what must I do to get this sent to the database?
When I run Document.search_full_text("esp") in rails console, it works fine.
UPDATE
I added this in documents/find.html.erb :
<% $results.each do |m| %>
<p>The id is <%= m.id %>.</p>
<% end %>
I get an page that displays my menu, and only white after that...
You should understand that Rails tries to be as performant as possible. When you build a search it does NOT execute until you attempt to access the results of the search.
So you would do...
def find
#documents = Document.search_full_text(params[:ch_acte][:text])
end
Then in your find.html.erb you might do...
<% #documents.each do |document| %>
<%= document.name %>
<% end %>
The query is only executed when the #documents.each line is executed to retrieve the documents... i.e. only when it needs to be executed.
Spent the last day and a half scouring through the great threads here at SO and reading other things online and I'm still having trouble grasping the solution and how these moving pieces operate together.
I have a many-to-many relationship between County and TownshipRange through CountyTownshipRangeSurvey. This relationship is indicated in the routes file through nested resources.
I want the user to be able to delete the association between the two records, but the problem I'm running into is the delete link on the TownshipRange index page only accepts the township_range id value and not the associated county id value. Note that the correct county id param is present when viewing the index page (which contains the delete link).
How can I allow for this?
My hunch is that I need to make a change in two place. First, to the routes file so it will accept the county id and second, to the link_to in the view.
As a follow-up question... I realize I'm trying to put the functionality into the township_ranges_controller. Is this part of the problem? Would I be better served to move this functionality into a separate controller dedicated solely to the creation of the "through table" associations?
Thank you all for your invaluable insights! If you need any more code snippets, please let me know!
Model county.rb
class County < ApplicationRecord
has_many :township_ranges, through: :county_township_range_surveys
has_many :county_township_range_surveys
...
end
Model township_range.rb
class TownshipRange < ApplicationRecord
has_many :counties, through: :county_township_range_surveys
has_many :county_township_range_surveys
...
end
Model county_township_range_survey.rb
class CountyTownshipRangeSurvey < ApplicationRecord
belongs_to :county
belongs_to :township_range
...
end
Controller township_ranges_controller.rb
before_action :set_township_range, only: [:show, :edit, :update, :destroy]
...
# QUESTION: How do I find the appropriate county?
def destroy
#county = County.find(params[:id]) # This does not work
#county.township_ranges.destroy(#township_range)
redirect_to township_ranges_path(#county)
flash[:success] = "Township and Range has been deleted"
end
....
private
def set_township_range
#township_range = TownshipRange.find(params[:id])
end
...
related portion of routes.rb (expanded 20161124)
resources :states, shallow: true do
resources :counties do
resources :township_ranges do
resources :sections
end
end
end
Rails routes indicates the generated route does not look for the associated counties/:id for the DELETE action.
township_ranges GET /counties/:id/township_ranges(.:format) township_ranges#index
POST /counties/:id/township_ranges(.:format) township_ranges#create
new_township_range GET /counties/:id/township_ranges/new(.:format) township_ranges#new
edit_township_range GET /township_ranges/:id/edit(.:format) township_ranges#edit
township_range GET /township_ranges/:id(.:format) township_ranges#show
PATCH /township_ranges/:id(.:format) township_ranges#update
PUT /township_ranges/:id(.:format) township_ranges#update
DELETE /township_ranges/:id(.:format) township_ranges#destroy
It will look for the full route DELETE counties/:county_id/township_range/:id/ if I isolate the nesting by itself like this
resources :counties do
resources :township_ranges
end
but that keeps counties from being nested under states, which is not what I'm after...
township_range/index.html.erb
<td><%= link_to 'Destroy', township_range, method: :delete,
data: { confirm: "Delete #{township_range.township}
#{township_range.range} ?" } %></td>
development.log (with link update as requested by #Wish Zone)
Started GET "/counties/25/township_ranges" for 127.0.0.1 at 2016-11-23 15:23:20 -0600
Processing by TownshipRangesController#index as HTML
Parameters: {"id"=>"25"}
[1m[36mCounty Load (0.1ms)[0m [1m[34mSELECT "counties".* FROM "counties" WHERE "counties"."id" = ? LIMIT ?[0m [["id", 25], ["LIMIT", 1]]
Rendering township_ranges/index.html.erb within layouts/application
[1m[36mTownshipRange Load (34.5ms)[0m [1m[34mSELECT "township_ranges".* FROM "township_ranges" INNER JOIN "county_township_range_surveys" ON "township_ranges"."id" = "county_township_range_surveys"."township_range_id" WHERE "county_township_range_surveys"."county_id" = ?[0m [["county_id", 25]]
Rendered township_ranges/index.html.erb within layouts/application (72.6ms)
Completed 500 Internal Server Error in 113ms (ActiveRecord: 35.2ms)
ActionView::Template::Error (No route matches {:action=>"show", :controller=>"township_ranges", :county_id=>#<County id: 25, name: "comanche", abbreviation: nil, state_id: 35, created_at: "2016-11-22 16:24:52", updated_at: "2016-11-22 16:24:52">, :id=>nil} missing required keys: [:id]):
22: <td><%= link_to 'Edit', edit_township_range_path(township_range) %></td>
23: <%# QUESTION: Do I need to modify the link here so it somehow takes in the county id param? %>
24: <%# NOTE: This will likely also require some sort of customization to the routes file so that the county_id is passed as a param %>
25: <td><%= link_to 'Destroy', township_range_path(id: #township_range, county_id: #county), method: :delete,
26: data: { confirm: "Delete #{township_range.township} #{township_range.range} ?" } %></td>
27: </tr>
28: <% end %>
According to your situation Route should be
township_range_path(id: #township_range , county_id: #county)
and in controller you can find
County.find(params[:county_id])
Added by Spectator6: The final answer ended up being to remove the member do's I originally had in my routes. The working delete path ended up being
township_range_path(id: township_range, county_id: #county)
Thanks again #Wish Zone for your patience and for helping me understand the link_to path and routes a bit better :)
Hey all I am building out a CAD App in Rails 4 Ruby 2
I apologize if this is a noob question but i'm hung up here..
BACKGROUND
I have my main index page, acting as a multi view dispatch window, currently it Shows Active Pending and Cleared Calls. What I want to add now is a secondary page to list calls with a status of active and that I can eventually add some search fields to to look up previous calls.
my current calls_controller.rb index looks like:
class CallsController < ApplicationController
before_action :set_call, only: [:show, :edit, :update, :destroy]
# GET /calls
# GET /calls.json
def index
#calls = Call.all
#active_calls = #calls.select{|x| x.status == 'ACTIVE'}
#pending_calls = #calls.select{|x| x.status == 'PENDING'}
#clear_calls = #calls.select{|x| x.status == 'CLEAR'}
#approved_calls = #calls.select{|x| x.status == "APPROVED"}
end
**I HAVE THEN ADDED**
def histroy
#calls = Call.all
#approved_calls = #calls.select{|x| x.status == "APPROVED"}
end
I have added a view to the scaffold views and named that view history.hmtl.erb as shown below:
My routes.rb looks like
resources :calls do
collection do
get 'history'
end
end
I then created button to access the the new view:
<%= link_to history_calls_path, class: "btn btn-primary btn-nav", id: 'home-btn' do %>
<i class="fa fa-search"> Call History</i>
<% end %>
When I click the button to access the page i get the following error:
NoMethodError in Calls#history
undefined method `length' for nil:NilClass --> There are already calls with that status but it should return 0 if there are no approved calls
Extracted source (around line #2):
1
2
3
4
5
6
<div class="panel panel-warning" id="clr-calls-pnl">
<div class="panel-heading"><center><h4>Call History -- TOTAL CLEARED CALLS <span class="badge"><%= #approved_calls.length %></span></h4></center></div>
<table class="table" id="approve-table">
<thead>
<tr>
<th><center>Call Number</center></th>
Any help here would be much appreciated as i am still a bit of a noob but have never done this sort of thing before.
Thanks in advance.
EDIT #1:
I changed it to the .try(:lenght)
and now I get this:
NoMethodError in Calls#history
Showing /Users/TaurenLTD1/Desktop/TaurenLabs/PatrolProCAD/PatProCadApp/app/views/calls/history.html.erb where line #31 raised:
undefined method `each' for nil:NilClass
Extracted source (around line #31):
29
30
31
32
33
34
<tbody>
<% #approved_calls.each do |call| %>
<tr>
<td><center><%= call.call_number %></center></td>
<td><center><%= call.site_id %></center></td>
EDIT #2:
This is what the rails log is showing when I Open the History Page:
Started GET "/calls/history" for ::1 at 2015-11-21 19:46:55 -0700
Processing by CallsController#history as HTML
User Load (0.3ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT 1 [["id", 3]]
Rendered calls/history.html.erb within layouts/application (3.7ms)
Completed 200 OK in 131ms (Views: 129.9ms | ActiveRecord: 0.3ms)
You can use try here.
Change:
<%= #approved_calls.length %>
To:
<%= #approved_calls.try(:length) %>
For some reason your #approved_calls is nil and that's why you got that error. The above should prevent you from getting that error. But, a better approach would be to see why #approved_calls is getting nil value and fix that part and make sure you populate #approved_calls instance variable.
Update
Change your history action to this:
def history
#approved_calls = Call.where(status: 'APPROVED')
end
Final Update
You actually have a typo in your controller action. Change histroy to history.
I am building a Order management system. I recently posted a problem about adding a order to a customer. It seems that i have fixed it for 99%. if i look in my terminal it first finds the current customer ID and then creates a new order. The following result is.
Customer Load (0.2ms) SELECT "customers".* FROM "customers" WHERE "customers"."id" = ? LIMIT 1 [["id", 111]]
(0.1ms) begin transaction
SQL (0.4ms) INSERT INTO "orders" ("customer_id", "created_at", "updated_at") VALUES (?, ?, ?) [["customer_id", 111], ["created_at", "2015-11-12 13:28:21.185604"], ["updated_at", "2015-11-12 13:28:21.185604"]]
(8.2ms) commit transaction
But the problem is, it doesn't add the params. I did this intentionally just to check if my syntax would execute the following sql statement. But once i add params i get a common error "param is missing or the value is empty: order"
Here is my code:
Controller
def createorders
#customer = Customer.find(params[:id]) #find current id??
#current_user = Order.find(params[:id])
#orders = #customer.orders.new(order_params)
if #orders.save
flash[:notice] = "Subject created successfully"
redirect_to(:action => 'index')
else
#If save fails, redisplay the form so user can fix problems
render('new') #het zit in de new.html template
end
end
private
def order_params
#same as using "params[:subject]", expect that it:
# - raises an error if :subject is not present
# - allows listed attributes to be mass-assigned
params.require(:order).permit(:pakket, :verstuurt)
end
end
View
<%= link_to("<< Back to List", {:action => 'index'}, :class => 'back-link') %>
<div class="subject new">
<h2>Create Subject</h2>
<%= form_for(:order, :url=> {:action => 'createorders'}) do |f| %>
<table summary="subject form fields">
<tr>
<th>pakket</th>
<td><%= f.text_field(:pakket) %></td>
</tr>
<tr>
<th>verstuurt</th>
<td><%= f.text_field(:verstuurt) %></td>
</tr>
</table>
<div class="form-buttons">
<%= submit_tag("Create Subject") %>
</div>
<% end %>
</div>
Error message
ActionController::ParameterMissing in OrderController#createorders
param is missing or the value is empty: order
Extracted source (around line #107):
105
106
107
108
109
110
def order_params
params.require(:order).permit(:pakket, :verstuurt)
end
end
Serverside Log
Started GET "/order/createorders?id=111" for ::1 at 2015-11-13
11:58:30 +0100 Processing by OrderController#createorders as HTML
Parameters: {"id"=>"111"} Customer Load (0.2ms) SELECT
"customers".* FROM "customers" WHERE "customers"."id" = ? LIMIT 1
[["id", 111]] Completed 400 Bad Request in 5ms (ActiveRecord: 0.2ms)
ActionController::ParameterMissing (param is missing or the value is empty: order): app/controllers/order_controller.rb:107:in
order_params' app/controllers/order_controller.rb:44:in
createorders'
Rendered /Users/cecil/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/actionpack-4.2.4/lib/action_dispatch/middleware/templates/rescues/_source.erb
(8.3ms) Rendered
/Users/cecil/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/actionpack-4.2.4/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb (2.6ms) Rendered
/Users/cecil/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/actionpack-4.2.4/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb
(1.3ms) Rendered
/Users/cecil/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/actionpack-4.2.4/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb
within rescues/layout (68.2ms) Rendered
/Users/cecil/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/web-console-2.2.1/lib/web_console/templates/_markup.html.erb
(0.4ms) Rendered
/Users/cecil/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/web-console-2.2.1/lib/web_console/templates/_inner_console_markup.html.erb
within layouts/inlined_string (0.4ms) Rendered
/Users/cecil/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/web-console-2.2.1/lib/web_console/templates/_prompt_box_markup.html.erb
within layouts/inlined_string (0.4ms) Rendered
/Users/cecil/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/web-console-2.2.1/lib/web_console/templates/style.css.erb
within layouts/inlined_string (0.4ms) Rendered
/Users/cecil/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/web-console-2.2.1/lib/web_console/templates/console.js.erb
within layouts/javascript (60.3ms) Rendered
/Users/cecil/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/web-console-2.2.1/lib/web_console/templates/main.js.erb
within layouts/javascript (0.3ms) Rendered
/Users/cecil/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/web-console-2.2.1/lib/web_console/templates/error_page.js.erb within layouts/javascript (0.5ms) Rendered
/Users/cecil/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/web-console-2.2.1/lib/web_console/templates/index.html.erb
(124.2ms)
Thank you stackoverflow for showing me support. I am new with ruby, and i understand i am making noob mistakes. So pointing out flaws are welcome!
I was ignoring your minor, non-fatal issues earlier while I was focused on locating the major issue, but I'll include them now that the major issue is apparent.
First, I'll discuss Rails naming conventions a little bit. You have two models, which are named Customer and Order. You've used the singular form of the noun for these, which is good. Each instance of a model is one thing, so it should be singular. Your controller for the Order model actions, however, should be named with the plural form, so it should be called OrdersController. This is because it controls the actions related to all of your orders. This leads us to your createorders action, which would make a little more sense if it were named createorder, since it only creates one Order. Actually, though, the convention is to name that action create. The action is in your OrdersController, so we already assume that it deals with an Order instance. (When you have Rails automatically generate REST-ful routes for a model's controller with the resources function, it assumes you have an action named create.) Lastly, in your create method, the new Order instance that will be referenced in your view should be called #order instead of #orders, since it contains only one Order.
Now things get a little more complicated. Your param is missing error means exactly that. The parameters for the new Order instance are missing. The request to the server that is producing that error is a GET request that has only one parameter, which you're providing in your URL with ?id=111. Your form's data is not being submitted to the server with that GET request. You should be doing a POST request to create a new Order. I'm going to avoid further exploration (and speculation without seeing your full code) regarding why things aren't working right now and I'll just suggest some key adjustments. It's turning in to a bit a puzzle to figure out how your app works without seeing all of the pieces.
In routes.rb, you should have this line:
resources :customers, :orders
I've made minimal changes to the view you provided, which I assume is called show.html.erb and is in your app/views/customers folder:
<%= link_to("<< Back to List", {:action => 'index'}, :class => 'back-link') %>
<div class="subject new">
<h2>Create Subject</h2>
<%= form_for #order do |f| %>
<table summary="subject form fields">
<tr>
<th>pakket</th>
<td><%= f.text_field(:pakket) %></td>
</tr>
<tr>
<th>verstuurt</th>
<td><%= f.text_field(:verstuurt) %></td>
</tr>
</table>
<%= f.hidden_field :customer_id %>
<div class="form-buttons">
<%= submit_tag("Create Subject") %>
</div>
<% end %>
</div>
Here is the necessary code from customers_controller.rb to support it:
def show
customer = Customer.find params[:id]
#order = customer.orders.new
end
Notice, in the view, the parameter for form_for is the instance that was created in the controller. Also, I've added a hidden field to submit the customer_id with the new Order data.
Finally, your create action in orders_controller.rb might look like this:
def create
#order = Order.new(order_params)
if #order.save
flash[:notice] = "Subject created successfully"
redirect_to(:action => 'index')
else
render 'customers/show'
end
end
And your order_params method should be changed to include the customer_id parameter:
def order_params
params.require(:order).permit(:pakket, :verstuurt, :customer_id)
end
Notice that on a failed save, the action renders customers/show, because this is the page that they were on where the save failed. This will allow Rails to re-populate the form (in the same context) with the data that was present during the failed submission.
When submitting an answer I get this error:
ActiveRecord::RecordNotFound (Couldn't find Question with ID=answer):
app/controllers/questions_controller.rb:6:in `show'
From what I understand I either made a error with passing an argument from the form or
didn`t define it correctly in my controller.
Would appreciate some help finding this bug, thanks in advance!
Questions_Controller:
class QuestionsController < ApplicationController
def index
end
def show
#question = Question.find(params[:id])
#choices = #question.choices
end
def answer
#choice = Choice.find(:first, :conditions => { :id => params[:id] })
#answer = Answer.create(:question_id => #choice.question_id, :choice_id => #choice.id)
if Question.last == #choice.question
render :action => "thank_you"
else
question = Question.find(:first, :conditions => { :position => (#choice.question.position + 1) })
redirect_to question_path(:id => question.id)
end
end
end
views/questions/show.html.erb :
<div data-role="content">
<div align="center">
<h3><%= #question.question %></h3>
</div>
<br><br>
<ul data-role="listview">
<% #choices.each_with_index do |c, i| %>
<% i = i + 1 %>
<li data-theme="c">
<%= link_to "#{i}. #{c.choice}", answer_questions_path(:id => c.id) %>
</li>
<% end %>
</ul>
</div>
::EDIT::
This happens when I try to select a choice & submit an answer while on the first question.
Started GET "/questions/1" for 127.0.0.1 at Thu Dec 01 01:38:36 -0500 2011
Processing by QuestionsController#show as
Parameters: {"id"=>"1"}
SQL (0.6ms) SELECT name
FROM sqlite_master
WHERE type = 'table' AND NOT name = 'sqlite_sequence'
Question Load (0.3ms) SELECT "questions".* FROM "questions" WHERE "questions"."id" = 1 LIMIT 1
Choice Load (10.8ms) SELECT "choices".* FROM "choices" WHERE ("choices".question_id = 1)
Rendered questions/show.html.erb within layouts/application (28.8ms)
Completed 200 OK in 424ms (Views: 118.0ms | ActiveRecord: 11.6ms)
Started GET "/questions/answer?id=1" for 127.0.0.1 at Thu Dec 01 01:38:38 -0500 2011
Processing by QuestionsController#show as
Parameters: {"id"=>"answer"}
Question Load (0.1ms) SELECT "questions".* FROM "questions" WHERE "questions"."id" = 0 LIMIT 1
Completed in 10ms
ActiveRecord::RecordNotFound (Couldn't find Question with ID=answer):
app/controllers/questions_controller.rb:6:in `show'
Hope this helps.
My best guess is that you don't have a route correctly setup. Assuming that you're using Rails 3 and you're using resources, you need to do add the following:
resources :questions do
member do
put 'answer'
end
end
This will create a route like /questions/#{id}/answer.
Answer is not an HTTP verb, so using resources in your routes will not create a route to your answer action.
Edit based on comment:
First, if you're updating or creating data, you should use put or post. It's a bad idea to modify data on the server with a get. Secondly, I assume that you would be doing an answer per question. If that is the case, you should do the action on a member, not a collection. Also, in your answer action, you have params[:id]. You won't get params[:id] if you try to do an action on a collection rather than a member.