2012-01-19_08.01.49
Methods always return something, even nil
Put an at sign in front of variable makes it an instance variable
Class names get upper case – but when you enter rails generate command you can make the model name lower case
model: class name is singular – this is a particular row in the database
The generators are pretty forgiving
But the pluralization is important – you need to get that right
Model names are singular, table name is plural
Model methods: new, save, all, first,
Landmark.all -> talks to the table
To populate database in the rails console:
a = Landmark.new a.name = "Soldier Field" a.cost = 50 a.save
Undocumented trick in rails console: type name of class and press enter. If there is a model class with that name, it will print info about class
Another way: pass a hash
x = Landmark.new(:name => "Art Institute", :cost => 18)
Hash keys: Could be strings, people prefer symbols
symbol: like a lightweight string, faster to process, fewer methods you could run on it, like a number that’s easy to read
You still call x.save with hash
He used “x” as variable name twice
The old value went away
Another way:
Landmark.create(:name =>"City Hall", :cost => 0 )
Parentheses are optional in Ruby
Using create will save it in one step
What if I have another landmark with the same name as an existing one?
Landmark.find(4) where the arg is the ID number
The IDs start at one
To list them:
y Landmark.all
To list one
y Landmark.find(3) x = Landmark.find(2) call x.name = "jdjd" x.save
How to delete?
x = Landmark.find 4 x.destroy
But variable x still has data in it, even though that record is not in database
Or you could call Landmark.destory(id_name)
You could do Landmark.find_by_cost(15)
That would show anything with a cost of 15
Landmark.find_by_$FIELD($ARG)
The find_by methods will only give you the first that it finds
It dynamically makes methods via code generation = kind of metaprogramming
Some of the HTML is done by app/views/layouts/application.html.erb
The yield method puts our stuff in there
You can have different layouts for different controllers
How to select one and show just that one?
Go to controller file:
@landmark = Landmark.find(ID)
Make a new route:
get "landmarks/5/show", :controller => 'landmarks;, :action => 'show'
That’s hard-coded
get "landmarks/:id/show", :controller => 'landmarks;, :action => 'show'
What about the controller? How to put that :id in call to Landmark.find?
Now, 5 is hard-coded in the controller. Here is the log:
Started GET "/landmarks/3/show" for 127.0.0.1 at 2012-01-19 09:25:56 -0600 Processing by LandmarksController#show as HTML Parameters: {"id"=>"3"} Landmark Load (36.0ms) SELECT "landmarks".* FROM "landmarks" WHERE "landmarks"."id" = ? LIMIT 1 [["id", 5]] Rendered landmarks/show.html.erb within layouts/application (8.6ms) Completed 200 OK in 152ms (Views: 113.2ms | ActiveRecord: 36.3ms)
The second time is better:
Started GET "/landmarks/3/show" for 127.0.0.1 at 2012-01-19 09:27:06 -0600 Processing by LandmarksController#show as HTML Parameters: {"id"=>"3"} Landmark Load (0.1ms) SELECT "landmarks".* FROM "landmarks" WHERE "landmarks"."id" = ? LIMIT 1 [["id", 5]] Rendered landmarks/show.html.erb within layouts/application (4.0ms) Completed 200 OK in 10ms (Views: 8.8ms | ActiveRecord: 0.4ms)
If you changed :id in the route to :jeff, you would get the same thing in the log except for timestamps, and
Parameters: {"id"=>"3"}
would be
Parameters: {"jeff"=>"3"}
So to get the id we send, put this in controller:
@landmark = Landmark.find params[:id]
or
@landmark = Landmark.find( params[:id])
Model: singular, controller is plural
Model: name.rb, Controller: names_controller.rb
To catch a bad :id in controller show method:
if Landmark.exists?(param[:id]) @landmark = Landmark.find(params[:id]) else @landmark = Landmark.first end
That’s not the best way, but it works for now
Change routes.rb:
get "landmarks", :controller => 'landmarks', :action => 'index'
Or
get "landmarks" => 'landmarks#index'
And for the other one:
get "landmarks" => 'landmarks#show'
This is only for Rails 3 and beyond
Put a link that takes us back to the home page:
IN the show template for show.html.erb
You could remove /public/index.html
and put this in routes.rb:
root :to => 'landmarks#index'
rake has a lot of good stuff
rake routes
will print the routes
ericm@finance:~/ruby/codeAcademy/tth/second$ rake routes root / {:controller=>"landmarks", :action=>"index"} landmarks GET /landmarks(.:format) {:action=>"index", :controller=>"landmarks"} GET /landmarks/:id/show(.:format) {:controller=>"landmarks", :action=>"show"}
so if the route has a name, you can use it in a link_to method call
<%= link_to 'Home', landmarks_url %>
You need to run rake routes to see which ones have names
You could also do landmarks_path
This will just create a relative URL
You can give a route a name:
get "landmarks/:id/show" => 'landmarks#show', :as => :landmark
In the index when we iterate, we could:
<li><%= link_to landmark.name, "/landmarks/#{landmark.id}/show" %></li>
or
<li><%= link_to landmark.name, landmark_url(landmark) %></li>
or
<li><%= link_to landmark.name, landmark_url(landmark.id) %></li>
Let’s add a form
What should the URL be?
/landmarks/new
So put it in the routes.rb
get "landmarks/new", :as => :new_landmark
So put an action “new” in the landmarks controller
and create a file app/views/landmarks/new.html.erb
When to add a controller instead of a new method?
Is the activity still related to the same type? Or is it a new thing?
We do not need the “form” tag
<%= form_for @landmark do |form| %> <%= form.label :name %> <%= form.text_field :name %> <%= form.submit %> <% end %>
Go to routes:
post "landmarks" => 'landmarks#create'
put a create method in the controller
The new method was just for the form
In log:
Started POST "/landmarks" for 127.0.0.1 at 2012-01-19 11:14:23 -0600 Processing by LandmarksController#create as HTML Parameters: {"utf8"=>"✓", "authenticity_token"=>"FO5+OlbNWa0g7xO3a/2hWtXnIPx7u5Ml0du2Oij74Eg=", "landmark"=>{"name"=>"fghd"}, "commit"=>"Create Landmark"} Completed 500 Internal Server Error in 3ms
ActionView::MissingTemplate (Missing template landmarks/create, application/create with {:handlers=>[:erb, :builder, :coffee], :formats=>[:html], :locale=>[:en, :en]}. Searched in:
* “/home/ericm/ruby/codeAcademy/tth/second/app/views”
):
In parameters, there is
"landmark"=>{"name"=>"fghd"}
So our data is in the hash. The data is the value of a hash, which itself is another hash
Do this:
params[:landmark][:name]
You could do:
form_data = params[:landmark] @landmark.name = form_data[:name]
At the end of the create method
redirect_to root_url
the URL must be a named route
Started POST "/landmarks" for 127.0.0.1 at 2012-01-19 11:22:44 -0600 Processing by LandmarksController#create as HTML Parameters: {"utf8"=>"✓", "authenticity_token"=>"FO5+OlbNWa0g7xO3a/2hWtXnIPx7u5Ml0du2Oij74Eg=", "landmark"=>{"name"=>"fghd"}, "commit"=>"Create Landmark"} SQL (3.4ms) INSERT INTO "landmarks" ("cost", "created_at", "name", "updated_at") VALUES (?, ?, ?, ?) [["cost", nil], ["created_at", Thu, 19 Jan 2012 17:22:44 UTC +00:00], ["name", "fghd"], ["updated_at", Thu, 19 Jan 2012 17:22:44 UTC +00:00]] Redirected to http://localhost:3000/ Completed 302 Found in 160ms
Images:
app/assets/images
The tag is
<%= image_tag 'tower.jpg' %> <%= image_tag 'tower.jpg', :size => '200x100' %>
How to get rid of a landmark:
Is the show.html.erb
<%= link_to "Toast", landmark_url(@landmark) %>
In routes:
delete "landmarks/:id", :as => :landmark
But there is a name conflict in the route – we will look at this next week
To update in console: could get it, change it, save
or: call method update_attribute
Image from Wikimedia, assumed allowed under Fair Use. Image from the Vatican Virgil, a 5th century manuscript of poems by Virgil.