Ruby on Rails 简介

网上冲浪含两方,冲浪者(client-side)和给冲浪者提供服务的服务器(server-side)。client这边浏览器上看到的网站背后是html+javascript+css,ctrl+u 就能看到源代码——这是前端,程序员把想象中的网页界面编程出来。后端(server)涉及的是处理网页请求(例如浏览器输入xxx.com/sign_up发起一个GET注册网页的请求),逻辑与数据处理。这让网站变得动态(例如登陆新浪微博后,你看到的是自己的主页,周杰伦登陆完看到的是周杰伦的主页)。

古人发明了一些框架,让前后端编程都变得容易。常见的前端框架有Vue.js, React; 后端有Node.js, Django/Flask(Python), PHP和这次侧重的Ruby on Rails。 相比其他后端框架,Rails 更有full-stack的感觉,因为它也能做很出色的前端(一些gem库)而无需搭配前端js框架。

搞一个Ruby on rails项目并不是简单地新建一个.rb文件,而是在命令行输入:

rails new helloworld(项目名称)

(如何装rails问chatgpt, 没记错的话大概是得预先装Ruby和gem(类似Python与pip)再gem install rails

这时候会新建一个文件夹helloworld,里面有一大堆子文件夹和文件。这也是Rails魅力之一:大多数重复的东西它都帮你准备好了,程序员可以最快速地搭建web server。

这时候输入

rails s (server的简称)

就能在本地某端口看到搭建好的靓丽的Rails标志。

 

MVC

Rails采用很典型的Model-View-Controller架构。很多software(包括native 和web)都是这个结构。

Model我理解为数据模型,本质上是一个class, 侧重数据。它规定某个对象需要什么样的数据,以及定义常用的methods。 它位于./app/models文件夹。

拿学习网站举例子,这是一个User的Model:

class User < ApplicationRecord
	# ...
  validates :email, uniqueness: true, format: { with: URI::MailTo::EMAIL_REGEXP }
  validates :username, length: { in: 2..100 }
  validates :learning_goal, length: { maximum: 1700 }

  has_many :completed_lessons, through: :lesson_completions, source: :lesson
  has_many :likes, dependent: :destroy
  belongs_to :path, optional: true
	#...
  def progress_for(course)
    @progress ||= Hash.new { |hash, c| hash[c] = CourseProgress.new(c, self) }
    @progress[course]
  end

  def completed?(lesson)
    completed_lessons.pluck(:id).include?(lesson.id)
  end

如代码,每个用户需要独特的邮箱,长度在2-100的用户名,不超过1700字符的学习任务。用户有一些数据,比如“完成了多少课程”的数据。它也归属一些数据,比如“path”。 它也有一些方法,比如completed?在数据库检查它是否有完成某个课程。

有了这个model,在建立数据库的时候会更清楚。例如在 ./db/seeds/schema.rb就建立了这样的数据库:

create_table "users", id: :serial, force: :cascade do |t|
    t.string "email", limit: 255, default: "", null: false
    t.string "encrypted_password", limit: 255, default: "", null: false
    t.string "reset_password_token", limit: 255
    t.datetime "reset_password_sent_at", precision: nil
    t.datetime "remember_created_at", precision: nil
    t.integer "sign_in_count", default: 0
    t.datetime "current_sign_in_at", precision: nil
    t.datetime "last_sign_in_at", precision: nil
    t.string "current_sign_in_ip", limit: 255
    t.string "last_sign_in_ip", limit: 255
    # ...
end

Controller定义了一堆方法。它和view紧密连接。比如在./config/routes.rb我们规定www.learn.com/dashboard的时候去寻找叫做users的controller,并调用show方法

get 'dashboard' => 'users#show'

Rails会自动寻找 ./app/controllers/users_controller.rb 文件的叫做UsersController的class(case sensitive!)。Controller是逻辑的核心。它算出来一些变量,比如在这的@courses,投射给views.

class UsersController < ApplicationController
  before_action :authenticate_user!

  def show
    @courses = current_user.path.courses
    @project_submissions = current_user.project_submissions.includes(:lesson).order(created_at: :desc)
  end
end

找到show之后会自动找./app/view/users/show.html.erb文件,这是view——展示在前端的界面。这是.html.erb文件,HTML embedded with Ruby。跟HTML不同的是,它里面嵌入逻辑和来自controller的变量,所以网站实现动态

<%= title('Dashboard') %>

<%= render CardComponent.new(classes: 'mb-16') do |card| %>
<% card.with_body do %>
<div class="flex items-center flex-col md:flex-row gap-4">
    <%= render User::AvatarComponent.new(current_user:, classes: 'w-20') %>
    <h2 class="truncate w-full basis-2/5 text-xl text-center md:text-left md:pl-4 font-medium text-gray-700 dark:text-gray-300" data-test-id="profile-username"><%= current_user.username %></h2>
    <%= render User::LearningGoalComponent.new(current_user:) %>
</div>
<% end %>
<% end %>

<%= render partial: 'skill', collection: @courses, as: :course %>

<%= render 'project_submissions', project_submissions: @project_submissions %>

 

 

Comments

Popular Posts