rails new NOM_DE_L_APP
rails new NOM_DE_L_APP --webpack
rails new NOM_DE_L_APP --database=postgres
- Coding the views?
- Coding the controllers?
- Coding the models?
π 3 - 2 - 1
rails generate model song title year:integer
What are the 2 created files?
π The migration and the model.
What is the rails command you should type then?
rails db:migrate
Q4 - How do you add a category
(ex: "rock"
, "electro"
, etc..) to your songs table using the correct Rails generator?
rails g migration AddCategoryToSongs category
What is the created file?
π a new migration
What is the rails command you should type again?
rails db:migrate
# models/song.rb
class Song < ApplicationRecord # Add the validation
validates :title, presence: :true
end
Now crash-test your model:
song = Song.new
song.valid?
song.errors.messages
song.title = "hey jude"
song.save
- The Router is routing the HTTP request to "controller#action"
- The action is getting data from models
- Everything starts with an HTTP Request
- The action is rendering the view
π 3 - 1 - 2 - 4
- Verb
- Url
- Header
- Body
# config/routes.rb
get "/songs" => "songs#index"
post "/songs" => "songs#create"
π No, verbs are differents.
π GET requests have no body. Data can only be sent via the url's query string (visible to users)
HTTP request: GET /search?query=thriller
Routing:
# config/routes.rb
get "/search" => "songs#search"
Controller:
class SongsController < ApplicationController
def search
# TODO
@songs = Song.where(title: params[:query])
end
end
HTTP request: GET /songs/named/thriller
Routing:
# config/routes.rb
get "/songs/named/:name" => "songs#search"
Controller:
class SongsController < ApplicationController
def search
# TODO
@songs = Song.where(title: params[:name])
end
end
# config/routes.rb
# TODO: Give us the details of the 7 routes generated with: resources :songs
# HINT: HTTP-verb "url" => "controller#action"
get "/songs", to: "songs#index"
get "/songs/:id", to: "songs#show"
get "/songs/new", to: "songs#new"
post "/songs", to: "songs#create"
get "songs/:id/edit", to: "songs#edit"
patch "songs/:id", to: "songs#update"
delete "songs/:id", to: "songs#destroy"
rails routes
rails generate controller songs
class SongsController < ApplicationController
def index
@songs = Song.all
end
def show
@song = Song.find(params[:id])
end
end
Q16 - What are the 2 requests needed to create a new song? Implement the songs#new
and songs#create
actions.
class SongsController < ApplicationController
def new
@song = Song.new
end
def create
@song = Song.new(song_params)
if @song.save
redirect_to songs_path
else
render 'new'
end
end
private
def song_params
params.require(:song).permit(:title, :year, :category)
end
end
π Any user can add inputs in the HTML using the browser's inspector before submitting a form. If you guess that Github has an admin boolean column to its users table, you could tweak the edit form to grant yourself admin rights on Github π± This actually happened in 2012 when Github was on Rails 2, which led to the strong params from Rails 3 on!
@song = Song.new
Now what is the HTML code generated by:
<%= form_for @song do |f| %>
<%= f.text_field :title %>
<%= f.submit %>
<% end %>
Fill the blanks:
<form action="/songs" method="post">
<input type="text" name="song[title]" value=" ">
<input type="submit" value="Create song">
</form>
Imagine that:
@song # => <#Song: id: 18, title: "Hey jude", year: 1968, category: "rock">
Now what is the HTML code generated by:
<%= form_for @song do |f| %>
<%= f.text_field :title %>
<%= f.submit %>
<% end %>
Fill the blanks:
<form action="/songs/18" method="patch">
<input type="text" name="song[title]" value="Hey jude">
<input type="submit" value="Update song">
</form>
- We don't want our visitors to destroy or update reviews, just to create ones.
- We don't want a separate index page to list all reviews or a show page to display each review. Instead, we want to display reviews on the show page of each song, for better UX.
Generate your Review
model in the terminal. It should have only a content:string
and a song:references
(= the foreign key).
rails g model review content:text song:references
Run the migration
rails db:migrate
Add validation/associations
- Add a validation for the presence of a content
- Add associations between
Review
andSong
class Song < ApplicationRecord
has_many :reviews
end
class Review < ApplicationRecord
belongs_to :song
validates :content, presence: :true
end
Generate the reviews controller
rails g controller reviews
Add the necessary routes (donβt forget we donβt want the 7 CRUD actions for reviews)
# config/routes.rb
resources :songs do
resources :reviews, only: [:new, :create]
end
Now code your controller:
class ReviewsController < ApplicationController
before_action :set_song
def new
@review = Review.new
end
def create
@review = Review.new(review_params)
@review.song = @song
if @review.save
redirect_to song_path(@song)
else
render 'new'
end
end
private
def set_song
@song = Song.find(params[:song_id])
end
def review_params
params.require(:review).permit(:content)
end
end
Add a songβs reviews on its show page:
<h1><%= @song.title %></h1>
<p><%= @song.year %></p>
<p><%= @song.category %></p>
<h2>Here are the reviews for this song:</h2>
<ul>
<% @song.reviews.each do |review| %>
<li><%= review.content %></li>
<% end %>
</ul>