-
Stwórz nowy prohjek
cd ˜/workspace rails _5.0.0_ new sample_app cd sample_app/
rails server
-
Modify Gemfile
source 'https://rubygems.org' gem 'rails', '5.1.4' gem 'puma', '3.9.1' gem 'sass-rails', '5.0.6' gem 'uglifier', '3.2.0' gem 'coffee-rails', '4.2.2' gem 'jquery-rails', '4.3.1' gem 'turbolinks', '5.0.1' gem 'jbuilder', '2.7.0' group :development, :test do gem 'sqlite3', '1.3.13' gem 'byebug', '9.0.6', platform: :mri end group :development do gem 'web-console', '3.5.1' gem 'listen', '3.1.5' gem 'spring', '2.0.2' gem 'spring-watcher-listen', '2.0.1' end group :production do gem 'pg', '0.20.0' end # Windows does not include zoneinfo files, so bundle the tzinfo-data gem gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby]
-
bundle install --without production
-
git init git add . git commit -m "Initialize repository"
-
Adding a hello action to the Application controller. app/controllers/application_controller.rb
def hello render html: "hello, world!" end
-
Setting the root route. config/routes.rb
root 'application#hello'
-
git commit -am "Add hello" git push heroku create git push heroku master
-
Static pages
-
To get started with static pages, we’ll first generate a controller
rails generate controller StaticPages home help
-
The Static Pages controller automatically updates the routes file (config/routes.rb)
See ... static_pages/home
-
Layouts
-
Dodaj do app/views/static_pages/home.html.erb
<% provide(:title, "Home") %> <h1>Sample App</h1> <p> This is the home page </p>
-
Setting the root route to the Home page. config/routes.rb
Rails.application.routes.draw do root 'static_pages#home' get 'static_pages/home' get 'static_pages/help' get 'static_pages/about' end
-
git add . git commit -m "Finish static page" # git push git push heroku
-
Site navigation
<!DOCTYPE html> <html> <head> <title><%= yield(:title) %></title> <%= csrf_meta_tags %> <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %> <%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %> <!--[if lt IE 9]> <script src="//cdnjs.cloudflare.com/ajax/libs/html5shiv/r29/html5.min.js"> </script> <![endif]--> </head> <body> <header class="navbar navbar-fixed-top navbar-inverse"> <div class="container"> <%= link_to "sample app", '#', id: "logo" %> <nav> <ul class="nav navbar-nav navbar-right"> <li><%= link_to "Home", '#' %></li> <li><%= link_to "Help", '#' %></li> <li><%= link_to "Log in", '#' %></li> </ul> </nav> </div> </header> <div class="container"> <%= yield %> </div> </body> </html>
-
Downloading an image rails.png.
curl -o app/assets/images/rails.png -OL railstutorial.org/rails.png
-
Add hyperlink by image_tag
<%= link_to image_tag("rails.png", alt: "Rails logo"), 'http://rubyonrails.org/' %>
-
Bootstrap and custom CSSAdding the bootstrap-sass gem to the Gemfile
gem 'bootstrap-sass', '3.3.7'
and runbundle install
-
Add styleshit to app/assets/stylesheets/custom.scss
touch app/assets/stylesheets/custom.scss
and add@import "bootstrap-sprockets"; @import "bootstrap"; /* universal */ body { padding-top: 60px; } section { overflow: auto; } textarea { resize: vertical; } .center { text-align: center; } .center h1 { margin-bottom: 10px; }
-
Dodaj do app/views/static_pages/home.html.erb
<div class="center jumbotron"> <h1>Welcome to the Sample App</h1> <h2> This is the home page. </h2> <%= link_to "Sign up now!", '#', class: "btn btn-lg btn-primary" %> </div> <%= link_to image_tag("rails.png", alt: "Rails logo"), 'http://rubyonrails.org/' %>
-
Add to app/assets/stylesheets/custom.scss
/* typography */ h1, h2, h3, h4, h5, h6 { line-height: 1; } h1 { font-size: 3em; letter-spacing: -2px; margin-bottom: 30px; text-align: center; } h2 { font-size: 1.2em; letter-spacing: -1px; margin-bottom: 30px; text-align: center; font-weight: normal; color: #777; } p { font-size: 1.1em; line-height: 1.7em; }
-
Converts the text of logo to uppercase and modifies its size, color, and placement add to app/assets/stylesheets/custom.scss
/* header */ #logo { float: left; margin-right: 10px; font-size: 1.7em; color: #fff; text-transform: uppercase; letter-spacing: -1px; padding-top: 9px; font-weight: bold; } #logo:hover { color: #fff; text-decoration: none; }
-
Partials
Add ne filles:
app/views/layouts/_shim.html.erb
app/views/layouts/_header.html.erb
app/views/layouts/_footer.html.erb
<!--[if lt IE 9]> <script src="//cdnjs.cloudflare.com/ajax/libs/html5shiv/r29/html5.min.js"> </script> <![endif]-->
-
<%= render 'layouts/shim' %>
-
<header class="navbar navbar-fixed-top navbar-inverse"> <div class="container"> <%= link_to "sample app", '#', id: "logo" %> <nav> <ul class="nav navbar-nav navbar-right"> <li><%= link_to "Home", '#' %></li> <li><%= link_to "Help", '#' %></li> <li><%= link_to "Log in", '#' %></li> </ul> </nav> </div> </header>
-
<footer class="footer"> <small> Footer </small> <nav> <ul> <li><%= link_to "About", '#' %></li> <li><%= link_to "Contact", '#' %></li> </ul> </nav> </footer>
-
Change app/views/layouts/application.html.erb
<!DOCTYPE html> <html> <head> <title><%= yield(:title) %></title> <%= csrf_meta_tags %> <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %> <%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %> <%= render 'layouts/shim' %> </head> <body> <%= render 'layouts/header' %> <div class="container"> <%= yield %> <%= render 'layouts/footer' %> </div> </body> </html>
-
Add
/* footer */ footer { margin-top: 45px; padding-top: 5px; border-top: 1px solid #eaeaea; color: #777; } footer a { color: #555; } footer a:hover { color: #222; } footer small { float: left; } footer ul { float: right; list-style: none; } footer ul li { float: left; margin-left: 15px; }
-
Layout links
<%= link_to "Help", help_path %>
and add config/routes.rbget '/help', to: 'static_pages#help'
-
User signup: A first step
rails generate controller Users new
-
Add to config/routes.rb
get '/signup', to: 'users#new'
-
<%= link_to "Sign up now!", signup_path, class: "btn btn-lg btn-primary" %>
-
<% provide(:title, 'Sign up') %>
-
Modeling users
-
Command for making a model is generate model, which we can use to generate a User model with name and email attribute
rails generate model User name:string email:string
One of the results of the generate command is a new file called a migration.
The full data model represented by the migration:
We can run the migration, known as “migrating up”, using the db:migrate command as follows: -
rails db:migrate
-
We can see the structure of the database by opening development.sqlite3
with DB Browser for SQLite http://sqlitebrowser.org/
rails console --sandbox User.new user = User.new(name: "Przemysław Spurek", email: "spurek@example.com") user.valid? user.save user ser.name user.email user.updated_at User.create(name: "Aaa", email: "aaa@example.org") foo = User.create(name: "Bbb", email: "bbb@example.org") foo.destroy
-
Finding user objects
User.find(1) User.find(3) User.find_by(email: "spurek@example.com") User.first User.all
-
Updating user objects
user # Just a reminder about our user's attributes user.email = "mhartl@example.net" user.save user user.created_at user.updated_at
-
user.update_attributes(name: "The Dude", email: "dude@abides.org") user.name user.email
-
user.update_attribute(:name, "El Duderino")
-
User validations
- Add to app/models/user.rb
-
VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i
http://www.rubular.com/ -
VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i validates :email, presence: true, length: { maximum: 255 }, format: { with: VALID_EMAIL_REGEX }, uniqueness: { case_sensitive: false }
-
rails test
- Database indices When creating a column in a database, it is important to consider whether we will need to find records by that column. Consider, for example, the email attribute created by the migration. When we allow users to log in to the sample app, we will need to find the user record corresponding to the submitted email address. Unfortunately, based on the naive data model, the only way to find a user by email address is to look through each user row in the database and compare its email attribute to the given email—which means we might have to examine every row (since the user could be the last one in the database). This is known in the database business as a full-table scan, and for a real site with thousands of users it is a Bad Thing.
-
The email index represents an update to our data modeling
rails generate migration add_index_to_users_email
-
Add to db/migrate/[timestamp]_add_index_to_users_email.rb
class AddIndexToUsersEmail < ActiveRecord::Migration[5.0] def change add_index :users, :email, unique: true end end
-
rails db:migrate
-
rails test
-
Delete all from test/fixtures/users.yml
-
rails test
-
Ensuring email uniqueness by downcasing the email attribute
before_save { self.email = email.downcase }
-
Adding a secure password
Most of the secure password machinery will be implemented using a single Rails method called has_secure_password, which we’ll include in the User model. The only requirement for has_secure_password to work its magic is for the corresponding model to have an attribute called password_digest.
rails generate migration add_password_digest_to_users password_digest:string
-
rails db:migrate
-
To make the password digest, has_secure_password uses a state-of-the-art hash function called
bcrypt.
To use bcrypt in the sample application, we need to add the bcrypt gem to our Gemfilegem 'bcrypt', '3.1.12'
-
bundle install
-
Add to app/models/user.rb
has_secure_password
-
rails test
-
Add to test/models/user_test.rb
def setup @user = User.new(name: "Example User", email: "user@example.com", password: "foobar", password_confirmation: "foobar") end
-
rails test
-
Minimum password standards
test "password should be present (nonblank)" do @user.password = @user.password_confirmation = " " * 6 assert_not @user.valid? end test "password should have a minimum length" do @user.password = @user.password_confirmation = "a" * 5 assert_not @user.valid? end
-
rails test
-
validates :password, presence: true, length: { minimum: 6 }
-
rails test
-
Creating and authenticating a user
rails console User.create(name: "Michael Hartl", email: "mhartl@example.com", password: "foobar", password_confirmation: "foobar") user = User.find_by(email: "mhartl@example.com") user.password_digest user.authenticate("not_the_right_password") user.authenticate("foobaz") user.authenticate("foobar") !!user.authenticate("foobar")
-
Adding some debug information to the site layout
<%= debug(params) if Rails.env.development? %>
-
Make the debug output look nice
/* mixins, variables, etc. */ $gray-medium-light: #eaeaea; @mixin box_sizing { -moz-box-sizing: border-box; -webkit-box-sizing: border-box; box-sizing: border-box; } /* miscellaneous */ .debug_dump { clear: both; float: left; width: 100%; margin-top: 45px; @include box_sizing; }
-
Adding a Users resource to the routes file config/routes.rb
Rails.application.routes.draw do root 'static_pages#home' get '/help', to: 'static_pages#help' get '/about', to: 'static_pages#about' get '/contact', to: 'static_pages#contact' get '/signup', to: 'users#new' resources :users end
-
-
Create app/views/users/show.html.erb
< @user.name %>, <%= @user.email %>
-
Add to app/controllers/users_controller.rb
def show end
-
Add to app/controllers/users_controller.rb
def show @user = User.find(params[:id]) end
-
Add a “globally recognized avatar”, or Gravatar.
Add to app/views/users/show.html.erb<% provide(:title, @user.name) %> <h1> <%= gravatar_for @user %> <%= @user.name %> </h1>
-
Add to app/helpers/users_helper.rb
# Returns the Gravatar for the given user. def gravatar_for(user) gravatar_id = Digest::MD5::hexdigest(user.email.downcase) gravatar_url = "https://secure.gravatar.com/avatar/#{gravatar_id}" image_tag(gravatar_url, alt: user.name, class: "gravatar") end
-
<% provide(:title, @user.name) %> <div class="row"> <aside class="col-md-4"> <section class="user_info"> <h1> <%= gravatar_for @user %> <%= @user.name %> </h1> </section> </aside> </div>
-
Add to app/assets/stylesheets/custom.scss
/* sidebar */ aside { section.user_info { margin-top: 20px; } section { padding: 10px 0; margin-top: 20px; &:first-child { border: 0; padding-top: 0; } span { display: block; margin-bottom: 3px; line-height: 1; } h1 { font-size: 1.4em; text-align: left; letter-spacing: -1px; margin-bottom: 3px; margin-top: 0px; } } } .gravatar { float: left; margin-right: 10px; } .gravatar_edit { margin-top: 15px; }
-
Signup form
Add to app/controllers/users_controller.rbdef new @user = User.new end
-
A form to sign up new users
<% provide(:title, 'Sign up') %> <h1>Sign up</h1> <div class="row"> <div class="col-md-6 col-md-offset-3"> <%= form_for(@user) do |f| %> <%= f.label :name %> <%= f.text_field :name %> <%= f.label :email %> <%= f.email_field :email %> <%= f.label :password %> <%= f.password_field :password %> <%= f.label :password_confirmation, "Confirmation" %> <%= f.password_field :password_confirmation %> <%= f.submit "Create my account", class: "btn btn-primary" %> <% end %> </div> </div>
-
app/assets/stylesheets/custom.scss
/* forms */ input, textarea, select, .uneditable-input { border: 1px solid #bbb; width: 100%; margin-bottom: 15px; @include box_sizing; } input { height: auto !important; }
-
def create @user = User.new(params[:user]) # Not the final implementation! if @user.save # Handle a successful save. else render 'new' end end
-
Since user_params will only be used internally by the Users controller and need not
be exposed to external users via the web, we’ll make it private using Ruby’s private keyword
def create @user = User.new(user_params) if @user.save # Handle a successful save. else render 'new' end end private def user_params params.require(:user).permit(:name, :email, :password, :password_confirmation) end
-
Signup error messages
Add to app/views/users/new.html.erb<% provide(:title, 'Sign up') %> <h1>Sign up</h1> <div class="row"> <div class="col-md-6 col-md-offset-3"> <%= form_for(@user) do |f| %> <%= render 'shared/error_messages' %> <%= f.label :name %> <%= f.text_field :name, class: 'form-control' %> <%= f.label :email %> <%= f.email_field :email, class: 'form-control' %> <%= f.label :password %> <%= f.password_field :password, class: 'form-control' %> <%= f.label :password_confirmation, "Confirmation" %> <%= f.password_field :password_confirmation, class: 'form-control' %> <%= f.submit "Create my account", class: "btn btn-primary" %> <% end %> </div> </div>
-
mkdir app/views/shared
-
Add to app/views/shared/_error_messages.html.erb
<% if @user.errors.any? %> <div id="error_explanation"> <div class="alert alert-danger"> The form contains <%= pluralize(@user.errors.count, "error") %>. </div> <ul> <% @user.errors.full_messages.each do |msg| %> <li><%= msg %></li> <% end %> </ul> </div> <% end %>
-
#error_explanation { color: red; ul { color: red; margin: 0 0 30px 0; } } .field_with_errors { @extend .has-error; .form-control { color: $state-danger-text; } }
-
Adding a signup route responding to POST requests
Add to config/routes.rbRails.application.routes.draw do root 'static_pages#home' get '/help', to: 'static_pages#help' get '/about', to: 'static_pages#about' get '/contact', to: 'static_pages#contact' get '/signup', to: 'users#new' post '/signup', to: 'users#create' resources :users end
-
add to app/views/users/new.html.erb
<% provide(:title, 'Sign up') %> <h1>Sign up</h1> <div class="row"> <div class="col-md-6 col-md-offset-3"> <%= form_for(@user, url: signup_path) do |f| %> <%= render 'shared/error_messages' %> <%= f.label :name %> <%= f.text_field :name, class: 'form-control' %> <%= f.label :email %> <%= f.email_field :email, class: 'form-control' %> <%= f.label :password %> <%= f.password_field :password, class: 'form-control' %> <%= f.label :password_confirmation, "Confirmation" %> <%= f.password_field :password_confirmation, class: 'form-control' %> <%= f.submit "Create my account", class: "btn btn-primary" %> <% end %> </div> </div>
-
Add to app/controllers/users_controller.rb
def create @user = User.new(user_params) if @user.save redirect_to @user else render 'new' end end
-
The flash
def create @user = User.new(user_params) if @user.save flash[:success] = "Welcome to the Sample App!" redirect_to @user else render 'new' end end
-
The first signup
rails db:migrate:reset
-
We can also use
<% flash.each do |message_type, message| %> <%= content_tag(:div, message, class: "alert alert-#{message_type}") %> <% end %>
-
Sessions
HTTP is a stateless protocol, treating each request as an independent transaction that is unable to use information from any previous requests. This means there is no way within the hypertext transfer protocol to remember a user’s identity from page to page; instead, web applications requiring user login must use a session, which is a semi-permanent connection between two computers (such as a client computer running a web browser and a server running Rails).
The most common techniques for implementing sessions in Rails involve using cookies,rails generate controller Sessions new
-
Add
Rails.application.routes.draw do root 'static_pages#home' get '/help', to: 'static_pages#help' get '/about', to: 'static_pages#about' get '/contact', to: 'static_pages#contact' get '/signup', to: 'users#new' get '/login', to: 'sessions#new' post '/login', to: 'sessions#create' delete '/logout', to: 'sessions#destroy' resources :users end
-
rails routes
-
Login form
<% provide(:title, "Log in") %> <h1>Log in</h1> <div class="row"> <div class="col-md-6 col-md-offset-3"> <%= form_for(:session, url: login_path) do |f| %> <%= f.label :email %> <%= f.email_field :email, class: 'form-control' %> <%= f.label :password %> <%= f.password_field :password, class: 'form-control' %> <%= f.submit "Log in", class: "btn btn-primary" %> <% end %> <p>New user? <%= link_to "Sign up now!", signup_path %></p> </div> </div>
-
Finding and authenticating a user Add to app/controllers/sessions_controller.rb
class SessionsController < ApplicationController def new end def create user = User.find_by(email: params[:session][:email].downcase) if user && user.authenticate(params[:session][:password]) # Log the user in and redirect to the user's show page. else # Create an error message. flash[:danger] = 'Invalid email or password combination' # Not quite right! render 'new' end end def destroy end end
-
Including the Sessions helper module into the Application controller.
class ApplicationController < ActionController::Base protect_from_forgery with: :exception include SessionsHelper end
-
Add to app/helpers/sessions_helper.rb
module SessionsHelper # Logs in the given user. def log_in(user) session[:user_id] = user.id end end
-
Add
def create user = User.find_by(email: params[:session][:email].downcase) if user && user.authenticate(params[:session][:password]) log_in user redirect_to user else flash.now[:danger] = 'Invalid email/password combination' render 'new' end end
-
Finding the current user in the session.
app/helpers/sessions_helper.rb# Returns the current logged-in user (if any). def current_user @current_user ||= User.find_by(id: session[:user_id]) end
-
Changing the layout links
<% if logged_in? %> # Links for logged-in users <% else %> # Links for non-logged-in-users <% end %>
-
Add to app/helpers/sessions_helper.rb
# Returns true if the user is logged in, false otherwise. def logged_in? !current_user.nil? end
-
<header class="navbar navbar-fixed-top navbar-inverse"> <div class="container"> <%= link_to "sample app", root_path, id: "logo" %> <nav> <ul class="nav navbar-nav navbar-right"> <li><%= link_to "Home", root_path %></li> <li><%= link_to "Help", help_path %></li> <% if logged_in? %> <li><%= link_to "Users", '#' %></li> <li class="dropdown"> <a href="#" class="dropdown-toggle" data-toggle="dropdown"> Account <b class="caret"></b> </a> <ul class="dropdown-menu"> <li><%= link_to "Profile", current_user %></li> <li><%= link_to "Settings", '#' %></li> <li class="divider"></li> <li> <%= link_to "Log out", logout_path, method: :delete %> </li> </ul> </li> <% else %> <li><%= link_to "Log in", login_path %></li> <% end %> </ul> </nav> </div> </header>
-
Adding the Bootstrap JavaScript library to application.js.
app/assets/javascripts/application.js
//= require jquery //= require bootstrap
-
Although our authentication system is now working, newly registered users might be confused, as they are not logged in by default.
Add app/controllers/users_controller.rbdef create @user = User.new(user_params) if @user.save log_in @user flash[:success] = "Welcome to the Sample App!" redirect_to @user else render 'new' end end
-
The log_out method.
Add to app/helpers/sessions_helper.rb# Logs out the current user. def log_out session.delete(:user_id) @current_user = nil end
-
Add to app/controllers/sessions_controller.rb
def destroy log_out redirect_to root_url end
-
Add to app/controllers/users_controller.rb
def edit @user = User.find(params[:id]) end
-
Create app/views/users/edit.html.erb
<% provide(:title, "Edit user") %> <h1>Update your profile</h1> <div class="row"> <div class="col-md-6 col-md-offset-3"> <%= form_for(@user) do |f| %> <%= render 'shared/error_messages' %> <%= f.label :name %> <%= f.text_field :name, class: 'form-control' %> <%= f.label :email %> <%= f.email_field :email, class: 'form-control' %> <%= f.label :password %> <%= f.password_field :password, class: 'form-control' %> <%= f.label :password_confirmation, "Confirmation" %> <%= f.password_field :password_confirmation, class: 'form-control' %> <%= f.submit "Save changes", class: "btn btn-primary" %> <% end %> <div class="gravatar_edit"> <%= gravatar_for @user %> <a href="http://gravatar.com/emails" target="_blank">change</a> </div> </div> </div>
-
Add
<%= link_to "Settings", edit_user_path(current_user) %>
-
Add to app/controllers/users_controller.rb
def update @user = User.find(params[:id]) if @user.update_attributes(user_params) # Handle a successful update. else render 'edit' end end
-
Successful edits (with TDD)
def update @user = User.find(params[:id]) if @user.update_attributes(user_params) flash[:success] = "Profile updated" redirect_to @user else render 'edit' end end
-
Allowing empty passwords on update
app/models/user.rbvalidates :password, presence: true, length: { minimum: 6 }, allow_nil: true
-
Authorization
Although the edit and update actions are functionally complete, they suffer from a ridiculous security flaw: they allow anyone (even non-logged-in users) to access either action and update the information for any user. -
Add to app/controllers/users_controller.rb
before_action :logged_in_user, only: [:edit, :update]
-
def logged_in_user unless logged_in? flash[:danger] = "Please log in." redirect_to login_url end end
-
Requiring the right user
Add to app/controllers/users_controller.rbbefore_action :correct_user, only: [:edit, :update]
-
# Confirms the correct user. def correct_user @user = User.find(params[:id]) redirect_to(root_url) unless @user == current_user end
- We can add the current_user? method.
Add to app/helpers/sessions_helper.rb
def current_user?(user) user == current_user end
-
and change correct_user method in app/controllers/users_controller.rb
# Confirms the correct user. def correct_user @user = User.find(params[:id]) redirect_to(root_url) unless current_user?(@user) end
-
Showing all users
Add to app/controllers/users_controller.rb/tt>before_action :logged_in_user, only: [:index, :edit, :update] def index end
-
Zadanie Co musimy dodać do funkcji index
def index @users = User.all end
-
Add app/views/users/index.html.erb
<% provide(:title, 'All users') %> <h1>All users</h1> <ul class="users"> <% @users.each do |user| %> <li> <%= gravatar_for user, size: 50 %> <%= link_to user.name, user %> </li> <% end %> </ul>
-
Add Gravatar helper specifying a size other than the default
app/helpers/users_helper.rbmodule UsersHelper # Returns the Gravatar for the given user. def gravatar_for(user, options = { size: 80 }) gravatar_id = Digest::MD5::hexdigest(user.email.downcase) size = options[:size] gravatar_url = "https://secure.gravatar.com/avatar/#{gravatar_id}?s=#{size}" image_tag(gravatar_url, alt: user.name, class: "gravatar") end end
-
Add to app/assets/stylesheets/custom.scss
/* Users index */ .users { list-style: none; margin: 0; li { overflow: auto; padding: 10px 0; border-bottom: 1px solid $gray-lighter; } }
-
Adding the URL to the users link
app/views/layouts/_header.html.erb
<li><%= link_to "Users", users_path %></li>
-
Sample users
gem 'faker', '1.7.3'
-
bundle install
-
Add to db/seeds.rb
User.create!(name: "Example User", email: "ppp@ppp.pl", password: "123456", password_confirmation: "123456") 99.times do |n| name = Faker::Name.name email = "example-#{n+1}@ror.org" password = "password" User.create!(name: name, email: email, password: password, password_confirmation: password) end
-
rails db:migrate:reset rails db:seed
-
Pagination
gem 'will_paginate', '3.1.6' gem 'bootstrap-will_paginate', '1.0.0'
-
bundle install
-
Add to app/views/users/index.html.erb
<%= will_paginate %> ... <%= will_paginate %>
-
def index @users = User.paginate(page: params[:page]) end
-
Administrative users and Deleting users
rails generate migration add_admin_to_users admin:boolean
-
Add to db/migrate/[timestamp]_add_admin_to_users.rb
class AddAdminToUsers < ActiveRecord::Migration[5.0] def change add_column :users, :admin, :boolean, default: false end end
-
rails db:migrate
-
Add admin to some user in db/seeds.rb
User.create!(name: "Example User", email: "example@railstutorial.org", password: "foobar", password_confirmation: "foobar", admin: true) 99.times do |n| name = Faker::Name.name email = "example-#{n+1}@railstutorial.org" password = "password" User.create!(name: name, email: email, password: password, password_confirmation: password) end
-
rails db:migrate:reset rails db:seed
-
Add to
<% if current_user.admin? && !current_user?(user) %> | <%= link_to "delete", user, method: :delete, data: { confirm: "You sure?" } %> <% end %>
-
Add to app/controllers/users_controller.rb
before_action :logged_in_user, only: [:index, :edit, :update, :destroy] def destroy User.find(params[:id]).destroy flash[:success] = "User deleted" redirect_to users_url end
-
Add to app/controllers/users_controller.rb
before_action :admin_user, only: :destroy ... private ... # Confirms an admin user. def admin_user redirect_to(root_url) unless current_user.admin? end
-
git add . git commit -m "Finish user edit, update, index, and destroy actions" git push heroku heroku pg:reset DATABASE heroku run rails db:migrate heroku run rails db:seed heroku restart
-
rails generate model Micropost content:text user:references
-
class Micropost < ApplicationRecord belongs_to :user end
-
class CreateMicroposts < ActiveRecord::Migration[5.0] def change create_table :microposts do |t| t.text :content t.references :user, foreign_key: true t.timestamps end add_index :microposts, [:user_id, :created_at] end end
-
rails db:migrate
-
class Micropost < ActiveRecord::Base belongs_to :user validates :user_id, presence: true validates :content, presence: true, length: { maximum: 140 } end
-
has_many :microposts
-
Ordering the microposts with add to app/models/micropost.rb
class Micropost < ApplicationRecord belongs_to :user default_scope -> { order(created_at: :desc) } validates :user_id, presence: true validates :content, presence: true, length: { maximum: 140 } end
-
Ensuring that a user’s microposts are destroyed along with the user.
add to app/models/user.rbhas_many :microposts, dependent: :destroy
-
Showing microposts
rails db:migrate:reset rails db:seed
-
rails generate controller Microposts
-
add to app/views/microposts/_micropost.html.erb
<li id="micropost-<%= micropost.id %>"> <%= link_to gravatar_for(micropost.user, size: 50), micropost.user %> <span class="user"><%= link_to micropost.user.name, micropost.user %></span> <span class="content"><%= micropost.content %></span> <span class="timestamp"> Posted <%= time_ago_in_words(micropost.created_at) %> ago. </span> </li>
-
<%= will_paginate @microposts %> <%= will_paginate %>
-
def show @user = User.find(params[:id]) @microposts = @user.microposts.paginate(page: params[:page]) end
-
Add to app/views/users/show.html.erb
<% provide(:title, @user.name) %> <div class="row"> <aside class="col-md-4"> <section class="user_info"> <h1> <%= gravatar_for @user %> <%= @user.name %> </h1> </section> </aside> <div class="col-md-8"> <% if @user.microposts.any? %> <h3>Microposts (<%= @user.microposts.count %>)</h3> <ol class="microposts"> <%= render @microposts %> </ol> <%= will_paginate @microposts %> <% end %> </div> </div>
-
add to db/seeds.rb
users = User.order(:created_at).take(6) 50.times do content = Faker::Lorem.sentence(5) users.each { |user| user.microposts.create!(content: content) } end
-
rails db:migrate:reset rails db:seed
-
/* microposts */ .microposts { list-style: none; padding: 0; li { padding: 10px 0; border-top: 1px solid #e8e8e8; } .user { margin-top: 5em; padding-top: 0; } .content { display: block; margin-left: 60px; img { display: block; padding: 5px 0; } } .timestamp { color: $gray-light; display: block; margin-left: 60px; } .gravatar { float: left; margin-right: 10px; margin-top: 5px; } } aside { textarea { height: 100px; margin-bottom: 5px; } } span.picture { margin-top: 10px; input { border: 0; } }
Zad
Manipulating microposts