CRUD in ruby on rails. Routing - ruby-on-rails

Working through the "Ruby on rails 3 essential training" I'm encountering an issue with my routes and URL's. I have created a sujects_controller with a 'list' action and a 'show' action. Within my localhost, when I enter in:
localhost:3000.subjects/list, I get an error, 'couldn't find Subject with id=list'
But, when I enter in:
localhost:3000.subjects. I get the list that should have come up when entering the first URL. Also, after entering this second URL, I have links for Show, Edit, and Delete. When I hover my mouse over the link "Show", at the bottom of the page, the future output reads localhost.3000/subjects(3). This link works. But, according to my instructors tutorials, it should read, localhost.3000/subjects/show/3. For some reason my links and/or actions, aren't working appropriately and I'm not sure why since I'm following the instructions.
Here is my subjects_controller.rb file:
class SubjectsController < ApplicationController
def index
list
render('list')
end
# def index
# show
# render('show')
# end
def list
#subjects = Subject.order("subjects.position ASC")
##subjects = Subject.all
end
def show
#subjects = Subject.find(params[:id])
end
def new
#subjects = Subject.new
end
def create
#subject = Subject.new(params[:subject])
if #subject.save
redirect_to(:action => 'list')
else
render('new')
end
end
end
Here is my list.html and show.html file:
<div class="subject list">
<h2>Subjects</h2>
<table class="listing" summary="Subject list">
<tr class="header">
<th> </th>
<th>Subject</th>
<th>Visible</th>
<th>Pages</th>
<th>Actions</th>
</tr>
<% #subjects.each do |subject| %>
<tr>
<td><%= subject.position %></td>
<td><%= subject.name %></td>
<td class="center"><%= subject.visible ? 'yes' : 'no' %></td>
<td class="center"><%= subject.pages.size %></td>
<td class="actions">
<%= link_to("Show", {:action => 'show', :id => subject.id}, :class => 'action show') %>
<%= link_to("Edit", '#', :class => 'action edit') %>
<%= link_to("Delete", '#', :class => 'action delete') %>
</td>
</tr>
<% end %>
</table>
Show.html
<%= link_to("<< Back to list", {:action => 'list'}, :class => 'back-link') %>
<div class="subject show">
<h2>Show Subject</h2>
<table summary="Subject detail view">
<tr>
<th>Name</th>
<td><%= #subject.name %></td>
</tr>
<tr>
<th>Position</th>
<td><%= #subject.position %></td>
</tr>
<tr>
<th>Visible?</th>
<td><%= #subject.visible ? 'true' : 'false' %></td>
</tr>
<tr>
<th>Created</th>
<td><%= #subject.created_at %></td>
</tr>
<tr>
<th>Updated</th>
<td><%= #subject.updated_at %></td>
</tr>
</table>
</div>
And my config/routes.rb file:
Rails.application.routes.draw do
root :to=>"demo#index"
get 'demo/index'
get 'demo/hello'
get 'demo/other_hello'
resources :subjects
get 'subjects/list' => 'subjects#list'
get 'subjects/list' => 'subjects#show'
get 'subjects/create' => 'subjects#create'
The instructor never shows his routes.rb file so I just started using the gets in order to get my actions to work. The resources :subjects wasn't able to take care of everything so I used GET. Also in my subjects_controller I def:index to render list. If I don't do that nothing works at all. I'm obviously new to all of this but love learning about it and any information is appreciated. I have looked at the rails routing from the guides but that hasn't helped me much. Its more the concept/theory of why my links/actions aren't working that I'd be very interested to hear about. Thanks for any info!

When you specify in routes
resources :subjects
It creates seven actions( index, new, create, create, show, edit, update, destroy)
When you call localhost:3000/subjects it ask routes where to go. And index action is called
/subjects subjects#index display a list of all subjects
And when you are saying localhost:3000/subjects/list
It expect id after /subjects as there are routes mapped to that
localhost:3000/subjects/5 when you will call this it will call show method in controller asking for record with id 5 in database
/subjects/:id subjects#show
If you want to see all the routes, from console type
rake routes
And if you want to define extra method like list as below
get 'subjects/list' => 'subjects#list'
and remove all other routes for list from routes file
And there are many more options to specify routes and to learn that this is your best friend
http://guides.rubyonrails.org/routing.html

The issue is your routes.rb file. When you specify resources :subjects you're adding many routes, one of which is get 'subjects/:id' => 'subjects#show'
Since routes take precedence depending on the order you write them (top to bottom) this is overwriting your get 'subjects/list' => 'subjects#list' line.
You also have many other redundant routes that are being overwritten there.
get 'subjects/list' => 'subjects#list'
get 'subjects/list' => 'subjects#show'
subjects#show won't ever be called because the route calling subjects#list will take precedence

It's because you first decleared
resources :subjects
and then the other routes.
In your case the best way to add routes to a resource is the following:
resources :subjects do
collection do
get :list, to: :show
end
end
This will generate:
# rake routes
list_subjects GET /subjects/list(.:format) subjects#show
subjects GET /subjects(.:format) subjects#index
POST /subjects(.:format) subjects#create
new_subject GET /subjects/new(.:format) subjects#new
edit_subject GET /subjects/:id/edit(.:format) subjects#edit
subject GET /subjects/:id(.:format) subjects#show
PATCH /subjects/:id(.:format) subjects#update
PUT /subjects/:id(.:format) subjects#update
DELETE /subjects/:id(.:format) subjects#destroy

Related

Facing issues with link_to "Edit" in rails

I am trying to display all the metrics in a table format with an edit option. But, I end up with the below error
In Index view, I am able to see all the data. But when I click on edit link, it is not redirecting to edit view where I have different columns to be showed.
index view:
<%= form_for :metrics_controller, url: metrics_path(#metric), method: :get do |f| %>
<table id="metrics">
<thead>
<tr id="AllMetricColumnNames">
<th id="CommentsColumn">Comments</th>
<th id="EditColumn">Edit</th>
</tr>
</thead>
<% #metricAll.each do |data| %>
<tr id="AllMetricValues">
<td id="Comments"><%= data.Comments %></td>
<td id="EditButton"><%= link_to "Edit", edit_metric_path(#metricAll) %></td>
<% end %>
</tr>
</table>
<% end %>
Controller:
class MetricsController < ApplicationController
def index
#metricAll = Metric.all
end
def show
#metric = Metric.find(params[:id])
end
def edit
#metric = Metric.find(params[:id])
end
private def post_params
params.require(:metric).permit(:Metric, :Comments)
end
end
routes:
root 'metrics#index'
get 'index' => 'metrics#index'
get 'edit' => 'metrics#edit'
resources :metrics
You're passing ALL the metrics for the edit route. Move from
<td id="EditButton"><%= link_to "Edit", edit_metric_path(#metricAll) %></td>
to
<td id="EditButton"><%= link_to "Edit", edit_metric_path(data) %></td>
data is the current metric in your code
According to your screenshot, the error is within the model.
Also, as mentioned by others, you should remove those get routes as the resources :metrics will generate the necessary routes for all your CRUD actions a.ka. for the index, show, edit, new, create, update, destroy.
My guess is that the metric.rb file has a belongs_to :automated_thresholding relationship but the metrics database table is missing the field automated_thresholding_id.
You should create a migration to add that field
add_reference :metrics, :automated_thresholding

Rails - routing error on delete

UPDATE rephrased after learning
I have extended my app with a new model called 'tag' (very similar set up as with comments in blog).
Intended outcome: the user to stay on the page when clicking the link_to button to delete a tag; I now get an routing error (below) and I don't understand why.
No route matches [DELETE] "/annotations/7/tags"
The TAG list is added to the view for ANNOTATIONS like this:
<div class="panel panel-default" style="background-color: white; word-wrap: break-word; font-size: 0.9em;">
<table id="tags" class="table table-hover">
<thead>
<tr>
<th>Tag</th>
<th>Type</th>
<th></th>
</tr>
</thead>
<tbody>
<% #annotation.tags.each do |tag| %>
<tr>
<td><%= tag.content %></td>
<td><%#= tag.tagtype_id | tag.tagtype.typeoftag %></td>
<td><%= link_to '', [tag.annotation, tag], method: :delete, data: { confirm: 'Please confirm deletion!' }, :class => "glyphicon glyphicon-remove" %></td>
</tr>
<% end -%>
</tbody>
</table>
</div>
These are my routes:
Rails.application.routes.draw do
root 'dashboard#index'
devise_for :users
resources :users, :documenttypes, :tagtypes
resources :documents do
resources :tags
get "pdf", on: :member
end
resources :annotations do
resources :comments, :tags
get "pdf", on: :member
end
get "annotations/:id/annotate" => "annotations#annotate", as: 'annotate'
get "angular_test", to: "angular_test#index"
mount PdfjsViewer::Rails::Engine => "/pdfjs", as: 'pdfs'
And the tags.controller
class TagsController < ApplicationController
def create
#annotation = Annotation.find(params[:annotation_id])
#comment = #annotation.tags.create(tag_params)
redirect_to annotation_path(#annotation)
end
def destroy
#annotation = Annotation.find(params[:annotation_id])
#comment = #annotation.tags.find(params[:id])
#comment.destroy
redirect_to annotate_path(#annotation)
end
private
def tag_params
params.require(:tag).permit(:content, :location, :tagtype_id)
end
end
UPDATE
The table in the view always has an empty row, which I cannot delete. I then get the routing error. With rows that were created when adding a tag, this does not happen and I can delete them. Why am I getting an empty row?
This needs to be done using AJAX (asynchronously), all you need to do is to have your destroy action to respond to javascript. You can do that by adding the remote option to the link for the deletion as below:
<td><%= link_to 'Delete', [tag.annotation, tag], method: :delete, remote: true, data: { confirm: 'Please confirm deletion!' }, :class => "glyphicon glyphicon-remove" %></td>
The remote: true option makes the request AJAX. Now on the controller side you need to respond with the resulting javascript code that you want to execute, probably hiding this row that you want to delete.
In the views folder, under the tags controller you need to create a file called destroy.js and in this file you specify the code that you want to be executed for handling this to hide for example that row.

Unable to pass param on clicking button in rails

I have a controller models_controller.rb as following:
class ModelsController < ApplicationController
def list
#models=["A","E","M","I"]
end
def get_config
Rails.logger.info(params[:model_id])
//some logic based on params[:model_id] value
end
end
The corresponding list.html.erb is as follows:
<table>
<thead>
<tr>
<th>Model</th>
<th></th>
</tr>
</thead>
<tbody>
<% #models.each_with_index do |model, index| %>
<tr>
<td><%= model %></td>
<td><%= button_to "view", {:controller => :models, :action => :get_config, :model_id => index }, :method => :get %></td>
</tr>
<% end %>
</tbody>
</table>
Each row of this table has a button, where upon clicking, I am passing the index of the element. But I am not been able to access it in the get_config method. Logger is printing an empty string. routes.rb is as follows:
DemoApp::Application.routes.draw do
get "models/list"
get "models/get_config"
get "models/list/:model_id" => "models#get_config"
end
What am I doing wrong? I am not able to figure that out.
Rails routes are matched in the order they are specified. So get "models/get_config" is catching the request before get "models/list/:model_id" => "models#get_config". Try changing the order to this:
DemoApp::Application.routes.draw do
get "models/list"
get "models/list/:model_id" => "models#get_config"
get "models/get_config"
end

Editing multiple records in one form - Rails

I'm trying to edit multiple records using one form, so the user can edit a few records then press submit at the end rather than after each individual one. I've posted my current code, and I get this error:
undefined method `connection_connection_path'
Controller
def show
#customer = Customer.find(params[:id])
#connection = #customer.connections
respond_to do |format|
format.html # show.html.erb
format.json { render json: #customer }
end
end
View
<table class="table">
<thead>
<th>Interface</th>
<th>Device</th>
<th>Speed</th>
<th>Site</th>
<th>Capable</th>
<th>Notes</th>
</thead>
<%= form_for(#connection) do |f| %>
<% #connection.each do |l| %>
<tr>
<td><%= l.interface %></td>
<td><%= l.device %></td>
<td><%= l.speed %></td>
<td><%= l.site.name%> </td>
<td><%= f.check_box :check %></td>
<td><%= f.text_field :notes %></td>
</tr>
<% end %>
<tr><%= f.submit %></tr>
</table>
<% end %>
routes
resources :connections
resources :sites
resources :customer_sites
resources :customers
root :to => "customers#index"
so where is your submit button?? and it should not done in show, maybe you might create a new method in your controller and do the multiple edit function.
The basic concept is when you have checks, you need to pass an array of your object to your method, and update them one by one. or you can do that using JS as well.
refer this railscast
http://railscasts.com/episodes/165-edit-multiple
and this stackoverflow
Rails 3 Edit Multiple Records in a Single Form
these resources you can get easily by google :D
if still have problem, just come and ask here again

How can I implement vanity URL's in a Rails application?

I want users to able to have a profile page at site.com/myNameHere. Rails looks for a controller named "myNameHere." Is it possible to setup routes.rb so that if the controller is not found, "myNameHere" gets sent as a parameter to another controller?
You can add a route like this:
map.profile_link '/:username', :controller => 'profiles', :action => 'show'
Be sure to add it low enough in the file, below your resources, that it doesn't interfere with other routes. It should be lowest priority. Next, you need to change your show action to use a username instead of id:
def show
#user = User.find_by_username(params[:username])
end
That's all there is to it. Happy coding!
UPDATE:
I've expanded this answer into a full blog post, Vanity URLs in Ruby on Rails Routes. I have additional code samples and a more thorough explanation.
Just thought I would update this for Rails 3. I have a field 'website' in my user model that is going to act as the vanity route, and I am going to route to a static page for each vanity route. I want to display all of a users 'events' if the vanity route is called.
#config/routes.rb
get '/:website', :controller => 'static_pages', :action => 'vanity'
#app/controllers/static_pages_controller.rb
def vanity
#user = User.find_by_website(params[:website])
if #user != nil #in case someone puts in a bogus url I redirect to root
#events = #user.events
else
redirect_to :root
end
end
#app/views/static_pages/vanity.html.erb
<h1><%= #user.website %> events</h1>
<table>
<tr>
<th>Title</th>
<th>Starts at</th>
<th>Description</th>
<th></th>
<th></th>
<th></th>
</tr>
<% #events.each do |event| %>
<tr>
<td><%= event.title %></td>
<td><%= event.starts_at %></td>
<td><%= event.description %></td>
</tr>
<% end %>
</table>
I think this is a good alternative if you don't want to use a gem.

Resources