How can I implement vanity URL's in a Rails application? - ruby-on-rails

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.

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

CRUD in ruby on rails. Routing

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

Ruby on rails-Tabular form for input taken from user

I want to print in tabular form the entries given by user. The table will contain 3 columns for name,registration number and classes attended, however the output is not as expected. Its first printing all the names and then all the registration numbers and so on. I want to print a name and the registration number according to name and classes attended.
</head><table width="100%">
<tr>
<th>NAME</th>
<th>REGISTRATION NUMBER</th>
<th>CLASSES ATTENDED</th>
</tr>
<tr>
<% #name_students.each do |t| %>
<th><%= t.name_student %></th><br>
<% end %>
<% #reg_nos.each do |t| %>
<th><%= t.reg_no %></th><br>
<% end %>
<% #classes_ats.each do |t| %>
<th><%= t.classes_at %></th><br>
<% end %>
</tr>
</table>
Here is my controller action.
class PagesController < ApplicationController
def home
#name_students = Page.all
#reg_nos = Page.all
#classes_ats = Page.all
end
def list
#name_students = Page.all
#reg_nos = Page.all
#classes_ats = Page.all
end
def add
Page.create(:name_student => params[:nam])
Page.create(:reg_no => params[:reg])
Page.create(:classes_at => params[:cls])
redirect_to :action => 'home'
end
end
If I understand what you're doing, you should probably have PagesController#home return something like #pages = Page.all object and display the data kind of like this:
<thead>
<tr>
<th>Name</th>
<th>Registration Number</th>
<th>Classes Attended</th>
</tr>
</thead>
<tbody>
<% #pages.each do |p| %>
<tr>
<td><%= p.name %></td>
<td><%= p.registration_number %></td>
<td><%= classes_attended(p.classes_attended) %></td>
</tr>
<% end %>
</tbody>
Above, classes_attended(p) is a call to a helper method that you would use to map the class names of the classes that student attended into an display-able array. Really, that kind of display logic might be better in a decorator, but a helper method should be fine for now.
Let me know if I've totally misunderstood what you're doing, and I'll delete my answer.
Edit to add:
Example index method:
def home
#pages = Page.all
end
Also, looking at your question again, is there a reason you're creating three Page objects with one attribute each instead of one Page object with all three attributes? It should probably look something like Page.create(:name_student => params[:nam], :reg_no => params[:reg], :classes_at => params[:cls]). That's pretty much the only way the solution I posted will work. Again, though, I might be totally misunderstanding what you're going for.

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

Couldn't find tasksadmins with id=15

I have two controllers: Tasksadmins and Workers.
I defined a table, is called: Tasksadmin, and has the parameters: admin_email, worker_email, task, done. the done option is check box.
in Tasksadmins controller, I defined:
def edit
#tasksadmin = Tasksadmin.find(params[:id])
end
in this controller, I can edit all the row of the table. it works fine!
in the Workerscontroller, I tried to define:
def edit
#tasksadmin = Tasksadmin.find(params[:id])
end
I did it because I want to get all of the parameters of the row, but I will let the worker an option to change only the parameter of done.
unfortunately, I got this error:
ActiveRecord::RecordNotFound in WorkersController#edit
Couldn't find Worker with id=15
I think I got it because the url is: localhost:3000/workers/15/edit
(pay attention to: workers/15/edit)
in order to understand where the problem is, I wrote the next word in my models/workers/edit.html.erb:
hello!
so I think the problem is with the work workers in the url :/
how can I fix it please?
UPDATE:
this is the index of the workerscontroller:
def index
#tasks_worker = Tasksadmin.where(:worker_mail => current_user.email)
respond_to do |format|
format.html # index.html.erb
format.json { render json: #workers }
end
end
this is index.html.erb:
<h1>Listing workers</h1>
<table>
<tr>
<th>Admin_mail</th>
<th>Task</th>
<th>Done</th>
<th></th>
<th></th>
<th></th>
</tr>
<% #tasks_worker.each do |task| %>
<tr>
<td><%= task.admin_mail %></td>
<td><%= task.task %></td>
<td><%= task.done %></td>
<td><%= link_to 'Edit', edit_worker_path(task) %></td>
</tr>
<% end %>
</table>
It seems like Worker with ID=15 doesn't exist.
Worker.find(params[:id])
Will raise ActiveRecord::RecordNotFound if that Worker doesn't exist.
You can go into the rails console and try:
Worker.find(15)
If you want to have find return nil instead of raising you can use:
Worker.find_by_id(params[:id])
I'm not too sure about this (maybe somebody can correct me), but I think
#tasksadmin = Tasksadmin.find(params[:id])
just defines the variable #tasksadmin.
Now, if you call the localhost:3000/workers/15/edit-URL, Rails is actually searching for a worker with ID 15 (Worker.find(15))
What do you want to accomplish?
I added this line in Workerscontroller:
load_and_authorize_resource :except => [:edit, :update]
and this line in Tasksadminscontroller:
load_and_authorize_resource :except => [:update, :show]

Resources