本文是一个Rails新手的学习笔记,主要是对过去一个月中学习内容的总结,包括:css
Agile Web Development with Rails 4html
Rails 101web
Rails for Zombies算法
水平有限, 错误再所不免(这也是我写出来的缘由啦 :D), 还请诸位多多指教.数据库
Rails 的开发速度很是快,但学习速度是很慢的。DHH曾经提到过:相比learnability,他更看重usability。DHH的15分钟开发博客程序确实激动人心,可是不通过全面的学习,想要作出合格可用的产品是不现实的。bootstrap
学习Rails究竟是在学习什么? 在我看来,主要是如下几个:数组
这是学习任何一个web框架,都要完成的任务。Rails相比其余框架,须要学习的点就是MVC 和 routes 文件的写法。浏览器
Rails框架强制你使用MVC模式进行开发,那什么是真正的MVC呢?那就是:ruby
用户请求的永远是controller,服务器返回给浏览器的永远是view.服务器
以用户注册为例,直觉的作法是用户点击首页的注册连接,转到有表格的view,用户填写信息以后submit,请求转到controller中的特定action,处理请求以后根据结果转回注册页面或者自动登陆到首页。
这种作法并无彻底符合MVC,由于有经过硬编码的连接实现的view到view的跳转,Rails的作法是这样的:
点击首页的注册连接,跳转到users_controller
的 new,这个action计算用户须要填写的信息,初始化一个空的对象,转到new_html这个view,用户填写表格以后submit,请求转给create这个action,处理请求以后根据结果 redirect_to 到 new (重定向会让浏览器再次向服务器发起对controller下 new 的请求)或者自动登陆到首页。
永远是 view -> controller -> view 的处理流程。
这并非一个好例子,或许我该举一些“不在view中写业务逻辑、保持controller精简”之类的最佳实践,可是它们都被举烂了,我也就再也不多说,我举得这个例子或许能让你对MVC有多一些的思考。
routes.rb
这个文件无疑是任何 Rails 项目的灵魂, 我获得的建议是: 若是你打算研究一个 Rails 开源项目, 要打开的第二个文件永远是routes.rb
, 第一个固然是Gemfile
啦, :D.
这个文件的两个基本做用:
new_user_path
这样的写法,避免出现硬编码的连接controller
中的action
相对应.这就牵扯到了Rrails的一个重要特性: restful
. 之前写Servlet
, 常常会有/getUser?id=3
这样的连接, restful
的想法是, 既然自己已是GET
请求了, 连接何须再有get
呢. Rails就按照restful
的思路, 把连接变成了: GET users/:id
. 在使用该连接的时候, 用users_path(@user)
这样的写法来传递id
这个参数.
restful
固然还有更"高大上"的做用, 例如分布式系统下的容错性之类的, 可是对于新手, 这样理解设计者的初衷就行了: 就是将updateUserInfo?id=3
deleteUser?id=4
这样的连接, 转成PUT users/3
DELETE users/3
.
新手常常搞不清楚path
的写法, 尤为是出现各类nested resources
的时候, 在终端输入rake routes
, 就能够看到了正确写法了.
主要学习的点包括migration
, seeds.rb
, 表关系及查询语句的编写.
SQL无疑是很是好用的语言, 但有个致命的肯定: 三五人的小团队, 没有专门的DBA, 如何保证全部开发者的数据库设计是一致的? 固然, 有许多的作法能够解决这个问题, 这些作法中migration是最好的之一.
它的基本思路, 就是用ruby代码来作数据库设计(增长新的表, 增长索引, 改变某列的数据类型), 每次修改都放在单独的良好命名的文件之中, 只要将其归入版本管理, 经过rake db:migrate
命令, 就能够保证全部开发者的数据库设计师一致的.
同时借助seeds.rb
文件, 保证全部开发者的测试数据是一致的.
也就是表之间的主外键关系以及三范式的知足. 在我短暂的Rails开发旅程中, 大多数时间都花费在数据库设计上, 也使我对
程序 = 算法 + 数据结构
这一论断愈来愈信服.
Rails 提供了诸多功能方便开发者申明表之间的主外键关系, 包括has_many
belongs_to
has_many_through
等, 合理地利用该特性能够帮助你写出可读性很是好的代码, 例如在这样的主外键设计之下:
class Group < ActiveRecord::Base has_many :group_users has_many :members, :through => :group_users, :source => :user end class GroupUser < ActiveRecord::Base belongs_to :user belongs_to :group end class User < ActiveRecord::Base has_many :group_users has_many :participated_groups, :through => :group_users, :source => :group end
能够用current_user.participated_groups
这样十分天然的语句来获取当前登陆用户参加的社团.
这一点没什么好说的, 就两点:
find_by
返回的是找到的第一个值这也是学习Rails中的很重要的一个点, 选择Rrails是为了快速开发, 那为何不更快一点呢. devise
让你一份实现登录与注册, 邮箱验证, 密码找回; bootstrap-rails
让你两分钟提高网站的设计感; will_paginate
让你再也不操心分页的实现....
固然还有许多重要的点要学习, 可是都没有上面几个那样有提纲挈领的做用. 都放到下一节当细节说吧.
主要就是Sublime Text
了, 有几个插件很是好用, 明显提升效率. 我装了Emmet
, ERB Snippets
和Ruby on Rails snippets
三个插件, 主要是实现
PE
而后tab
能够自动生成<%= -%>
ER
而后tab
能够自动生成<% %>
ul>li*2>a
而后tab
能够打出:<li><a href=""></a></li> <li><a href=""></a></li>
has_many
之类的, 你们自行查看其官网的cheat_sheet
scope :graveyard, where(:show_location => true , :location => 'graveyard')
给列添加索引, 以提高性能
class Tweet < ActiveRecord::Base has_one :location, :dependent => :destroy, :foreign_key => :tweeter_id end class Location < ActiveRecord::Base belongs_to :tweet, :foreign_key => :tweeter_id end
dependent: :destroy
来设置外键依赖避免 N+1 issue
使用 Zombie.includes(:brain).all
,来代替直接Zombie.all
, 而后view
中each打印zombie.brain
, 以提高性能
update_attributes和update是同样的
参考这里 rake, 也可使用rake -T
查看
rake db:schema:dump
, 能够从如今的数据库建立schema文件rake db:setup
. 三件事: 建立数据库, 读取schema文件, 从'seeds.rb'导入种子数据concerns/current_cart_rb
中, 一方面是其中的方法在各个controller中共享, 其次防止其中的方法被当作action来调用. 注意该文件夹下的文件都是autoload
的, 不须要显式地写include
.callback
使set_cart
执行的.class CartsController < ApplicationController before_action :set_cart, only: [:show, :edit, :update, :destroy] rescue_from ActiveRecord::RecordNotFound, with: :invalid_cart def index @carts = Cart.all end private def invalid_cart logger.error { "Attempt to access invalid cart #{params[:id]}" } redirect_to store_path, notice: 'Invalid cart!' end end module CurrentCart extend ActiveSupport::Concern private def set_cart @cart = Cart.find(session[:cart_id]) rescue ActiveRecord::RecordNotFound @cart = Cart.create session[:cart_id] = @cart.id end end
def new if @cart.line_items.empty? redirect_to store_url, notice: 'Your cart is empty.' return #redirect_to不会自动return end @order = Order.new end
-before_filter
就是旧版本中的 before_action
- build
就是new
的别名
- save!
会引起RecordInvalid
异常, 而save
会返回boolean
值
- nil?
判断对象是否存在, 不存在的对象都是nil
的; empty?
判断是否为空字段,好比一个字符串是否为空串,或者一个数组中是否有值;object.blank?
至关于o
bject.nil?||object.empty?`
- 在befor类的钩子函数中,返回FALSE则不执行before后跟的操做, 此处容易出bug
能够用errors.add(:base, 'Line Items present')
添加错误信息, 在controller中能够经过@line_item.errors
来获取.
能够经过<body class='<%= controller.controller_name %>'>
来命名body的class, 方便scss的书写.
#view中 <%= f.select :pay_type, Order::PAYMENT_TYPES, prompt: 'Select a payment method' %> # model中 PAYMENT_TYPES = ['Check', 'Credit Card', 'Purchase Order'] validates :pay_type, inclusion: PAYMENT_TYPES
button_to
默认是POST
请求, link_to
默认是GET
请求.