Search By Label
pass
in Python functions as a placeholder for empty code.pass
prevents errors.pass
can be used to intentionally skip a block of code if a certain condition isn't met.%pip
and %conda
command that will run in the current kernel.%pip install geocoder
import sys
!{sys.executable} -m pip install geocoder
[11,22,31,224,44].each_with_index { |val,index| puts "index: #{index} for #{val}" if val < 30} index: 0 for 11 index: 1 for 22 => [11, 22, 31, 224, 44]
rails new jwt_rails_api --api
gem 'jwt', '~> 2.7' gem "bcrypt", "~> 3.1.7"
User
and Product
Modelsrails g model User username:string password:string rails g model Product name:string description:text
rails db:migrate
, our setup with models is complete, and our schema, found in db/schema.rb
, should now look similar to this:ActiveRecord::Schema[7.0].define(version: 2024_03_26_224534) do create_table "products", force: :cascade do |t| t.string "name" t.text "description" t.datetime "created_at", null: false t.datetime "updated_at", null: false end create_table "users", force: :cascade do |t| t.string "username" t.string "password_digest" t.datetime "created_at", null: false t.datetime "updated_at", null: false end end
jwt
Gem Wrapperapp/lib/json_web_token.rb
and looks like this:class JsonWebToken JWT_SECRET = Rails.application.secrets.secret_key_base def self.encode(payload, exp = 12.hours.from_now) payload[:exp] = exp.to_i JWT.encode(payload, JWT_SECRET) end def self.decode(token) body = JWT.decode(token, JWT_SECRET)[0] HashWithIndifferentAccess.new(body) end end
data = {"name"=>"Juanequex"} JsonWebToken.encode(data) # => "eyJhbGciOiJIUzI1NiJ9.eyJuYW1lIjoiQXBwU2lnbmFsIiwiZXhwIjoxNjg1NDI0MjI5fQ.zWJyFHH8Pa6phBOU99XgtRntyfZQSOTX4TdwOxFY9gY" JsonWebToken.decode(JsonWebToken.encode(data)) # => {"name"=>"Juanequex", "exp"=>1685424262}
User
ModelUser
model at app/models/user.rb
. All we need to do here is add the has_secure_password
class method:class User < ApplicationRecord has_secure_password end
User.create(username: "juanequex", password: "password") Product.create(name: "Rad Ruby", description: "A book collection of Ruby tips")
ApplicationController
at app/controllers/application_controller.rb
:class ApplicationController < ActionController::API before_action :authenticate rescue_from JWT::VerificationError, with: :invalid_token rescue_from JWT::DecodeError, with: :decode_error private def authenticate authorization_header = request.headers['Authorization'] token = authorization_header.split(" ").last if authorization_header decoded_token = JsonWebToken.decode(token) User.find(decoded_token[:user_id]) end def invalid_token render json: { invalid_token: 'invalid token' } end def decode_error render json: { decode_error: 'decode error' } end end
AuthenticationController
to which users can send requests and get a signed JSON Web Token from our server. This controller should be placed at app/controllers/authentication_controller.rb
and may look like this:class AuthenticationController < ApplicationController skip_before_action :authenticate def login user = User.find_by(username: params[:username]) authenticated_user = user&.authenticate(params[:password]) if authenticated_user token = JsonWebToken.encode(user_id: user.id) expires_at = JsonWebToken.decode(token)[:exp] render json: { token:, expires_at: }, status: :ok else render json: { error: 'unauthorized' }, status: :unauthorized end end end
rails g controller Product index
so we have something like:class ProductsController < ApplicationController before_action :authenticate def index @products = Product.all render json: @products end end
config/routes.rb
should look something like:Rails.application.routes.draw do post 'login', to: "authentication#login" get 'products', to: "products#index" end
curl -H "Content-Type: application/json" -X POST -d '{"username":"manny","password":"password"}' http://localhost:3000/login
{"error":"unauthorized"}
curl -H "Content-Type: application/json" -X POST -d '{"username":"juanequex","password":"password"}' http://localhost:3000/login
{"token":"eyJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoxLCJleHAiOjE2ODU0NTEyMTR9.1UEYAbmFOSF93yp9pJqNEzkdHr3rVqutPNZWRIPDYkY","expires_at":1685432077}
curl -H "Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoxLCJleHAiOjE2ODU0NTEyMTR9.1UEYAbmFOSF93yp9pJqNEzkdHr3rVqutPNZWRIPZYkY" http://localhost:3000/products
{"decode_error":"decode error"}
[{"id":1,"name":"Rad Ruby","description":"A book collection of Ruby tips","created_at":"2024-03-26T19:33:30.826Z","updated_at":"2024-03-26T19:33:30.826Z"}]
// app/assets/stylesheets/components/_turbo_progress_bar.scss
.turbo-progress-bar {
background: linear-gradient(to right, var(--color-primary), var(--color-primary-rotate));
}
// app/assets/stylesheets/application.sass.scss
// All the previous code
@import "components/turbo_progress_bar";
# app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
# Add this line to see the progress bar long enough
# and remove it when it has the expected styles
before_action -> { sleep 1 } # this is only to debug the progress bar, it can be removed.
--progress
option: --progress string Set type of progress output (auto, plain, tty). Use plain to show container output
(default "auto")
--progress=plain
will show the output of the run commands that were not loaded from the cache. This can also be done by setting the BUILDKIT_PROGRESS
export BUILDKIT_PROGRESS=plain
--no-cache
to your build to rerun the steps and redisplay the output:docker build --progress=plain --no-cache ...
DOCKER_BUILDKIT=0
in your shell, e.g.:DOCKER_BUILDKIT=0 docker build ...
export DOCKER_BUILDKIT=0
docker build ...
8.9 > 8.10
and this is true with the decimal numbers, but when talking about the version of a software this is not true because each number after the dot have individual meaning resulting that the version 8.9 < 8.10
const WebpackBar = require('webpackbar'); module.exports = { // Otras configuraciones... plugins: [ new WebpackBar() ] };
--progress
npx webpack --config ./webpack.config.core.js --progress
npm list webpack
find_or_initialize_by
method is a convenient way to find a record in a database based on certain conditions and, if not found, initialize a new instance of the model with those conditions set.# Example usage @user = User.find_or_initialize_by(email: 'example@example.com')