Rails 3: how to code a route path - ruby-on-rails

I'm creating a rails app and I can't figure out or find answer for this problem.
What is the route for:
#example = Example.find_by_notId(params[:notId])
I want my route to look better then /example/1 and would rather have it read /notId (where notId would be title or some other non-ID int). Normally I would use show_path but in my html <%= link_to image_tag(pic), show_path(example) %> doesn't work. Here is my code and it works when I hard code it into the URL (localhost:3000/notId) but I need a way to route it through a link. Any ideas?
Show
def show
#example = Example.find_by_title(params[:title])
end
Routes
match '/:notId', to: 'example#show', via: 'get'
_example.html.erb
<div class="example">
<% Movie.all.each do |example| %>
<%pic = example.title + ".jpg"%>
<%= link_to image_tag(pic), show_path(example) %>
<% end %>
e</div>

You probably need to override the :id param in your routes:
resources :examples, param: :title
This will generate routes like:
/examples/:title
/examples/:title/edit
Then in your views:
example_path(example.title)
Alternatively, you can change the method to_param(used for building urls) in your model:
class Example < ActiveRecord::Base
def to_param
title
end
end
This allows you to keep using example_path(example) (without .title)

Related

nested routes in rails linking to wrong model

If my route looks like this
get 'users/:id/doc/:id', to: 'users/docs#show', as: :show_doc
and if my show controller action looks like this
def show
user = User.find(params[:id]) #in this case it should be user id 6
doc = Doc.find(params[:doc_id]) #in this case it should be doc id 29
end
and if the link in the index view looks like this
<% user.docs.each do |i| %>
<%= link_to "#{i.id}", show_doc_path(user.id, i.id), target: :_blank %>
<% end %>
why does the link go to localhost:3000/users/29/doc/29?
The issue is that the route definition uses the same key (id) for both user id and document id. Use doc_id for document id and you should be good to go.
get 'users/:id/doc/:doc_id', to: 'users/docs#show', as: :show_doc

Rails - redirect to different page in same path

In my Rails project, I have two different pages that exist within the same path - one is an index of stores, the other is a store update page (though I don't use those exact names for them). The problem that I am having is that I am trying to add dynamic links to the index page for each store to take a user to the associated update page, but I created the routes manually (rather than use :resources) and both pages are listed under the same path in my Rails routes summary. How can I use the <%= link_to %> helper in this situation?
First off, here is the relevant routing information...
stores_study_sites_path GET /stores/study_sites(.:format) stores#study_sites
GET /stores/store_details/:id(.:format) stores#store_details
And from my routes file...
get 'stores/study_sites' => 'stores#study_sites'
get 'stores/store_details/:id' => 'stores#store_details'
The first route, 'study_sites' is an index page, 'store_details' is the update page.
The redirect is rendered as a partial on the study_sites page...
<% #store.each do |store| %>
<ul>
<li>
<%= store.name %></br>
<%= store.street %></br>
<%= store.city %> <%= store.state %></br>
<%= render "shared/store_details", :store => store %>
</li>
</ul>
<% end %>
And finally, the partial that I would like to use, but does not currently work...
<%= link_to "Build store profile", stores_study_sites_path(store.id) %>
The urls generated from this look like http://localhost:3000/stores/study_sites.26 whereas I need them to be http://localhost:3000/stores/store_details/26
I've gone through this basic procedure for a number of other redirects with no problem, but I've created these custom urls/routes, and now I'm in a bit of a pickle. In a situation like this, how do I specify which url in the path I want the link to route to?
As a follow-up question (keep in mind I'm really new to Rails), why is the store_details page falling under the stores_study_sites_path?
Thank you very much.
Be RESTful
When starting out with Rails try to avoid falling off the band wagon - most real world problems can be solved with the standard CRUD routes and RESTful representations. When you start creating a bunch of custom routes just for different representations then the quality tends to dip sharply.
A better URL scheme would be:
/stores # index of stores
/stores/1 # show a single store
/stores/1/details # index of details of a store.
/stores/1/details is what you would call a nested resource. Its very clear from the URL that we are looking something which belongs to a store.
You can declare the routes with:
resources :stores, shallow: true do
resources :details
end
You can then create a link to the details of a store with:
<%= link_to "Build store profile", store_details_path(#store) %>
http://guides.rubyonrails.org/routing.html#nested-resources
You can name your routes manually:
get 'stores/study_sites' => 'stores#study_sites', as: "first_route"
get 'stores/store_details/:id' => 'stores#store_details', as: "second_route"
Then use them:
<%= link_to "one", first_route_path %>
## this will generate http://localhost:3000/stores/study_sites
<%= link_to "two", second_route_path(5) %>
## this will generate http://localhost:3000/stores/store_details/5
You really should put this setup within the context of your controller in the routes:
#config/routes.rb
resources :stores do
get :study_sites, on: :collection #-> url.com/stores/study_sites
get :store_details, on: :member #-> url.com/stores/:id/store_details
end
... and then in the view:
<%= link_to "x", stores_store_sites_path %>
<%= link_to "y", stores_store_details_path(store.id) %>

Ruby on Rails: Find a record by an attribute not an id

I'm very new to rails so please be patient with me.
In short I'm trying to create a form in which guests to a wedding can enter a simple code (invite_code) and then RSVP. The from should take the invite_code and then take the use straight to the correct invites#show view.
So far so good, but I'm stuck trying to get rails to find a record by something other than and id, I want to find by invite_code. Say I've got an Invite with an id of 4 and an invite_id of 1234, the form is finding the correct record when I enter '4' into the from but not '1234'. Here's some code to explain:
routes.rb
get 'invites/search', to: 'invites#show', controller: :invites
form
...
<%= form_tag invites_search_path, method: :get do %>
<%= label_tag :invite_code, "#" %>
<%= text_field_tag :invite_code, nil %>
<%= submit_tag "Search", name: nil %>
<% end %>
...
invites_controller
...
def show
if params.has_key?(:invite_code)
#invite = Invite.find(params[:invite_code])
else
#invite = Invite.find(params[:id])
end
end
...
rake routes output
Prefix Verb URI Pattern Controller#Action
info_index GET /info/index(.:format) info#index
invites GET /invites(.:format) invites#index
POST /invites(.:format) invites#create
new_invite GET /invites/new(.:format) invites#new
edit_invite GET /invites/:id/edit(.:format) invites#edit
invite GET /invites/:id(.:format) invites#show
PATCH /invites/:id(.:format) invites#update
PUT /invites/:id(.:format) invites#update
DELETE /invites/:id(.:format) invites#destroy
invites_search GET /invites/search(.:format) invites#show
root GET / info#index
URL example
.../invites/search?utf8=%E2%9C%93&invite_code=1234
"utf8"=>"✓", "invite_code"=>"1234", "id"=>"search"
The application seems to be ignoring the invite_id part of if statement in the controller...
Any help appreciated, it's taken me a long time to get this far...
You've got a couple of options. find_by_invite_code will return you the first match:
Invite.find_by_invite_code(params[:invite_code]) # First match or nil
While where will give you all the matches as an Array
Invite.where(invite_code: params[:invite_code]) # Array of matches. May be empty
You can also use the following syntax for find_by:
Invite.find_by(invite_code: params[:invite_code]) # First match or nil
find uses id field by default, use where instead
if params.has_key?(:invite_code)
#invite = Invite.where(invite_code: params[:invite_code]).first
...
def show
if params.has_key?(:invite_code)
#invite = Invite.find_by(invite_code: params[:invite_code])
# find_by argument: value
# returns first match or nil
# same as find, where find searches by id
# Invite.find_by_invite_code params[:invite_code] is deprecated
else
#invite = Invite.find params[:id]
end
end
...

Rails URL helper for sorting filters

I have a table Companies with field city_id. I need in sorting companies by cities. I do next:
# companies_controller.rb
def sort_by_city
#cities = City.joins(:company).uniq
#companies = Company.where("city_id = ?", params[:city_id])
render 'index'
end
# routes.rb:
get '/companies/city/:city_id', to: 'companies#sort_by_city'
and in index.html.erb I try make links for this filter:
<% #cities.each do |city| %>
<li><%= link_to city.name, UNKNOWN_path(city.id) %> (<%= city.companies_count %>)
<% end %>
I want links like this: "www.site.com/companies/city/23"
What I must write instead of UNKNOWN_path? Or I do something wrong before (in controller or in routes.rb)?
You can give a name to your route with the as option :
For example :
get '/companies/city/:city_id', to: 'companies#sort_by_city', as: 'companies_city_sort'
And then use
companies_city_sort_path
Also, have a look at resourceful routing, it may be more adapted.
If you type rake routes in your terminal you can find the name of the current path.
Just look for the line where companies#sort_by_city is listed.

how to connect my model to my app

Hey all,(im a beginner in rails)
i've created a controller that look like that:
class HomeController < ApplicationController
def homepage
end
def showmsg
#postword = params[:p]
end
end
the showmsg view looks like that:
<%= #postword %>
and my homepage view looks like that:
<%= form_tag( {:controller => 'home', :action => 'showmsg'}, :method => "post") do %>
<%= text_field_tag(:p,#postword) %>
<%= submit_tag("post") %>
<% end %>
now i have a form that i can write something in it and it will show on the showmsg view.
i created a model with the param :posts with a :description "text" field too.
MY QUESTION is how do i implement the model in the code so any thing i write will be in a list with the things i wrote before, because now (obviously) anything if i write something its deleting the one i wrote before.
thank you all!
I would argue that you're approach is not very rail's like... so if you're learning rails... you're learning it wrong.
Make a Model. Call it "Message":
rails generate model Message content:string
remember to migrate (hopefully you have your databases setup properly):
rake db:migrate
Then in your controller, when you post, you can create message like this:
def create #instead of showmsg... 'create' is the standard name for this
Message.create(params[:message])
#messages = Message.all
end
This will create the message in the database, and then it will get all the messages out of the database and put them into #messages.
You need to edit your form so that it uses form_for. You need to pass it #message, which is an instance of Message.new that your first controller action created. You should call this new
In your create.erb.html file, you show all the messages like this:
<ul>
<% #messages.each do |message| %>
<li><%= message.content %></li>
<% end %>
</ul>
I actually wouldn't recommend showing all the messages in the create action - it should really happen in the index action and you should redirect... but we need to keep this simple. Just google this or watch some of Ryan's screencasts and you'll get it.
And you're done. This is the "Rails Way" to do things. It's best to learn it the way they want you to learn it.
I would also commend that you format your code properly by indenting, and start naming your methods to be real english. For example, showmsg is bad and show_message is a lot better.
If all of this is totally confusing, then just create a new project, and then type:
rails generate scaffold message content:string
It will basically build the application you want and a lot more. You can just read the code and see how they did it.
Hope it helps.
Your approach is not really rails like so some tweaks and fixes are needed. Suggestions: check rails approach to REST. The following code will work it is a little more rails like, but still not all the way there.
Generate a model
rails generate model Message postword:string
this will generate the model and create the migration necessary to create the table in the database.
Create the table
rake db:migrate
Define a post action
It will save the postword in the database. In your controller:
def create
#message = Message.create!(params[:message])
if #message.save
redirect_to "/home/showmsg"
else
render :action => "/home/homepage"
end
end
Create and instance of Message to use in your form
def homepage
#message = Message.new
end
Fix your form tag
<%= form_for #message, :url => "/home/create" do |f| %>
<%= f.label :postword %>
<%= f.text_field :postword %>
<%= f.submit "Create" %>
<% end %>
Now let's show the words in the showmsg page
In the controller select the postwords from the database:
def showmsg
#postwords = Message.all
end
Showing them: /showmsg.html.erb
<H1>postwords list</H1>
<ul>
<% #postwords.each do |p| %>
<li><%= p.postword %></li>
<% end %>
</ul>
Your routes.rb file will have this routes:
get "home/homepage"
get "home/showmsg"
post "home/create"
Define an attribute :new_text in a way similar to this:
class TheModel
# Virtual writer - everything assigned to this attribute
# will be added to self.text
#
def new_text=(v)
self.text += v.to_s
end
def new_text
"" # This is write-only attribute
end
end
Now, use the field 'new_text' in your form.
Of course, this is a very simple example. You should decide whether you want to add the content on every call to :new_text=, maybe some validation would help, the read accessor may need some care, and so on.
For some good guides which may help you start, see the site http://guides.rubyonrails.org/

Resources