全栈工程师成长记

编程重新定义人生

码字不易 5/26日记

Objective

完成:

  • 新功能 UserStory
  • 新功能原型稿
  • 前三季比赛作品内容维护
  • 客服回复

Reflective

情绪:波澜不惊

Interpretive

学到:

  1. 日常的运营中,有些问题不需要修改代码来解决,善于利用原有的功能规则,就可以巧妙的实现
  2. 框架也许只要一个人构思,但细节需要很多人填充
  3. 为自己做的事情赋予意义的深层原因在于,当千百个放弃的理由扑面而来的时候,你知道它们只不过是纸老虎,继而能从容淡定的继续做自己的事

Decisional

形容:断笔好久,又一次体会到码字不易,要重新练起来
努力:导航栏改版,新功能页面初稿铺开,读一本书

我回来了

上一次写博客是产品上线那个星期,这之后已经快半年的时间过去。连续20几个星期,全部工作都在围绕着产品的快速迭代进行,一如博客副标题所说的“编程重新定义人生”,过去的160多天着实再次重新定义了我的人生,然而这当中不论是技术的进步还是个人的成长,竟没有些许记录留下,想来着实有些可惜。从今天开始,继续写博客。——2017.05.25

半月记(第十九周&第二十周)

Objective

完成:产品上线

Reflective

情绪:高亢/紧张/兴奋/开心
低点:时间不够用

Interpretive

学到:有些事,自己没做过,你就根本不懂别人在说什么,那不是别人傻逼,而是自己傻逼。
领悟:
上周实在是忙到连写一两百字的周记都没时间,所以这次把第十九周和第二十周的周记一起来了。
这两个星期的工作都围绕着产品上线展开,除了要完善一些页面细节,更多的精力放在了运营、客服方面。不同于以往做练习项目,这次面对的是真正的商业项目,要为真实用户提供服务,于是又重新理解了一遍编程只占20%的含义——一个有价值的产品绝对不只是它背后的代码本身而已,它的价值更多体现在如何帮助人们解决问题/实现自我、推动行业发展与变革、创造社会价值等方面。在这样的前提下,真正重要的是“道”,而代码只是与之相关的“术”。
于是我将做产品这件事赋予一层又一层的意义,然后就开始“全栈”了,也就真的根本停不下来了。又因为思考的颗粒度变细,看到的细节变多,越发觉得有更多事情需要去做,所以即便很多时候“加班”到“天亮说晚安”,却也依然不觉得累。

Decisional

形容:虽美中不足,但值得鼓励。
努力:接下来要补充一些Web设计/用户体验方面的知识。

规划即梳理 第十八周周记

继续秉承闲话少说的理念,本周稍微不同于以往的是,因为进入了内测阶段,要把一部分的精力用于修复 Bug 以及思考产品的运营层面。也由于产品即将上线,要做的事情越来越多(体现在 Redmine 上的 Ticket 随之增长),一如笑来老师之前所说,对工作的规划其实就是对工作的梳理。面对长长的 Redmine 清单,要分出轻重缓急就是先规划好指挥官任务(紧急、重要),然后新开 Ticket 时只要判定是否跟指挥官任务直接有关就可以了。嗯,就这样。

少说多做 第十七周周记

这周主要的工作集中在做页面的自适应。

总结一:如果一个网站最终还是要做自适应,那么在写一个页面之前,就尽量考虑不同的分辨率之下的页面布局样式,不然后期调整起来会比较麻烦。

总结二:写功能也好,写样式也罢,想要写的越来越快,有什么方法?这几周一直在写页面,有一点感受,借用卖油翁的话就是——“无他,唯手熟尔”。

经历了五个星期,我们的项目终于开始进入内测阶段。今天看到内测成员在跟着课程内容做测试、提供反馈,还很认真的写博客记录心得,对我而言这既是压力也是动力。虽然最近的周记越来越“缩水”,不过我还是闲话少说,先接着干活了。

根本停不下来 第十六周周记

周一、完善后台管理页面

周二、写页面

周三、写页面

周四、写页面

周五、写页面

周六、改 layout&写手机版页面

周日、写手机版页面

根本停不下来

这周的关键词依旧是页面,也就是一直在做 Onboarding 的事情。对 Onboarding 来说,持续的重复这件事情不会显得无聊,相反的则是找到了上瘾的感觉,所以根本停不下来,按照以往的经验,写个周记至少要 2-4 个小时,这次就节省一点写周记的时间接着写页面好了。

忘掉你所知道的一切吧 第十五周周记

周一、写页面

技巧:修改页面内容显示宽度
在 bootstrap 中,如果想要全屏展示页面内容, 使用 .container-fluid class,居中显示使用.container class。

通常页面内容宽度在 960px 到 1280px 左右,如果导航栏使用 .container-fluid class ,则在浏览器显示宽度超过页面内容宽度(比如前面说的 1280px) 之后,导航栏的内容会被拉伸到和浏览器窗口同样的宽度,就会变得和页面内容不对齐,因此可以根据页面内容的样式改用 .container 或者重新给导航栏定义一个适合宽度的 class。

说到导航栏,如果给导航栏使用 .navbar-default class,默认的颜色是 #f8f8f8 ,把 #f8f8f8 换成自己想要的颜色值,就可以给导航栏“变脸”了,如果要把它变成透明色,改为 transparent即可 :

.navbar-default {
    background-color: transparent;
}

又,假设在网页的顶部设置了大面积的背景图,想要让导航栏和这个背景图融为一体,最简单的实现方法是将整个 navbar 的代码都移动(或者通过 renden 的方式)到这个背景图的 div 里即可。

周二、写页面

技巧:消除图片排列间距
症状:水平排列图片的时候,默认会出现一个空白间距,如果不想要这个间距的话,使用图片本身的 margin 是不行的,哪怕负数也不起作用。那该如何去除呢?


解法:假设将这些图片排在一个 div 里,设置一个 class,代码如下:

.no-spacing {
  letter-spacing: -8px;
}

然后在图片的父级 div 使用上面的 .no-spacing class 即可。

效果:

参考及延伸阅读:如何解决inline-block元素的空白间距

周三、写页面

技巧:将 CarrierWave 上传的图片按比例裁切

CarrierWave 配置文件默认的图片裁切方式是 resize_to_fit ,只需改为 resize_to_fill 即可将图片按照设定的比例裁剪,这样做虽然会导致部分图片内容被裁掉,但是可以保证图片不会变形。

app/uploaders/image_uploader.rb
  version :thumb do
    process :resize_to_fit => [200, 200]
    process :resize_to_fill => [200, 200]
  end

周四、完善用户资料功能

技巧:套用 layout

  • 针对单个 action:
app/controllers/groups_controller.rb
   def index
     @groups = Group.all
+    render layout: "you_layout"
   end
  • 针对单个 controller:
app/controllers/groups_controller.rb
class GroupsController < ApplicationController
 layout "you_layout"

   def index
     @groups = Group.all
   end
  • 针对一系列的 controller,在父级 controller 使用一次即可:
app/controllers/admin_controller.rb
  class AdminController < ApplicationController
    layout "you_layout"

因为子级 controller 会自动继承 class Admin::UsersController < AdminController

  • 针对 devise ,则需要修改 config/initializers/devise.rb
config/initializers/devise.rb
Devise.setup do |config|
略……
    Rails.application.config.to_prepare do
      Devise::SessionsController.layout "you_layout"
     Devise::RegistrationsController.layout  "you_layout" 
    end
end

周五、文案及细节调整

技巧:给不同的用户身份做不同的登录后重定向
之前有说过如何自定义 devise 的 redirect_to ,现在假设普通用户登录之后给他重定向到用户中心页面,而给管理员重定向到网站后台管理页面,只要在前面的基础上做一小小的判断即可:

app/controllers/registrations_controller.rb
  def after_sign_in_path_for(_user)
    if current_user.is_admin?
      admin_path #管理员路径
    else
      account_path #用户路径
    end
  end

周六、初学 Sketch

跟着一个 Sketch 教程实作,通过重复的小套路,只要两个小时就能做出一个和教程一样的营销邮件,实现了 Sketch 从新手到入门的跨越。

掌握了几个基本工具的使用:

  1. 矩形(调整背景色、边框、大小)
  2. 文本(换字体、大小、颜色)
  3. 分组(组合、排序、命名、重复使用)

同时还学会:

  1. 画布的建立、大小、背景色调整
  2. 参考线的建立、拖动与删除
  3. 建立可复用的符号
  4. 建立可复用的文本样式
  5. 文件的导出

忘掉你所知道的一切吧

“忘掉你所知道的一切吧”——出自《奇异博士》电影台词,这句话是莫度男爵对想要学习魔法却又傲慢的主角斯蒂芬医生说的,翻译成 xdite 老师的话就是“放下你的无效学习方式”,嗯,就是这样。

如何自定义 devise 的 redirect_to (以及遇到的坑)

方法

用 devise 自带功能修改密码,默认修改密码成功之后会跳转到 root_path,如果想要实现的是,修改完密码之后跳转到用户中心,比如 user_path 这样的路径。该如何实现呢?

devise 官方 wiki 给出了方法,两步搞定:

1.建立 registrations_controller.rb 让它继承 Devise 的方法

app/controllers/registrations_controller.rb
class RegistrationsController < Devise::RegistrationsController

  protected

    def after_update_path_for(resource)
      user_path #你的路径
    end
end

2.修改 routes.rb 定位到新的 controller

config/routes.rb
devise_for :users, :controllers => { :registrations => :registrations }

扩展

一、注册用户和修改密码使用的是 registrations controller,如果想要在注册用户之后跳转到特定的页面,参考以上步骤,使用下面的 method:

app/controllers/registrations_controller.rb
   def after_sign_up_path_for(resource)
     welcome_path #你的路径
   end

二、登录用户使用的是 sessions controller,如果想要在用户登录之后跳转到特定页面,方法跟上面的则不太一样,这里只需要修改 app/controllers/application_controller.rb ,增加以下 method:

app/controllers/application_controller.rb
  def after_sign_in_path_for(_user)
    account_path #你的路径
  end

遇到的坑

本来今天在实现这个修改密码的跳转功能是瞬间就可以实现的事情,但问题在于,由于使用了新的 registrations controller ,导致现在新用户无法注册(旧用户可以登录、修改密码)。

排错过程

1.注册的时候填写的用户邮件、用户名、密码全部符合规范,但是提交表单 simple form 会提示出现错误,而且错误框并没有定位在注册页面的任何一个栏位,说明是其它栏位出了问题。

2.小伙伴哲伟用自己的代码修改 registrations controller ,一切正常,可以注册。

3.在自己的功能分支 merge 小伙伴的分支,问题重现。

4.在 develop 分支 merge 小伙伴的分支,没有问题。到此,可以判断问题出现在自己的功能分支。

5.回溯自己的 commit ,发现有在 user model 里面增加了一个 phone column(用户手机号码)的 validate 限制。

6.结论:问题不在 registrations controller 。

7.解法:去除 validate 限制或者给注册页面增加相应的栏位。

8.总结:多遇到坑并尝试去解决总是好的,比如步骤 1 里面 simple form 提示框不在当前页面,这个之前就有遇到过,所以可以以此快速排除是栏位问题。

问题集

从7月开始学 rails 到现在陆陆续续遇到了各种各样的 bug 和问题,大部分已经发在博客上,有一些则是根本就没有记录的,还剩下的则是七零八落的丢在电脑里的各个位置,今天整理一下全部丢上来。


simple_form 栏位相关

注册页面提示:No input found for citext
原因:username 栏位的数据类型是 t.citext "username"
解法:为simpleform相关栏位加入 as: :string

-        <%= f.input :username, required: true, label:false,  :placeholder => "用户名"%>
+        <%= f.input :username, required: true, label:false,  :placeholder => "用户名", as: :string %>

加载 layout js \ css

错误提示:

Sprockets::Rails::Helper::AssetNotPrecompiled in Welcome#index

Showing /app/views/layouts/welcome.html.erb where line #9 raised:


Asset was not declared to be precompiled in production.
Add `Rails.application.config.assets.precompile += %w( welcome.css )` to `config/initializers/assets.rb` and restart your server

解法:按照报错提示给 config/initializers/assets.rb 加入相关的 css 和 js 文件名就可以了


pg 数据库相关

问:post 属于某个 group ,要将几个 group 下面的 post 全部导出。
答:SELECT * FROM public.posts WHERE group_id = 5 OR group_id = 6 OR group_id = 7


重命名heroku app

heroku apps:rename new-app-name


rake 相关

为文件添加 # TODO, # FIXME, # OPTIMIZE
运行 rake notes 就可以查看待办事项
rake notes:custom ANNOTATION=ZOMG
rake notes:todo


git 相关

查看 git 配置:
git config --list

通过编辑器修改配置:
atom ~/.gitconfig

查看 git 已经追踪的文件:
git ls-files


bundle 相关

问题:运行 bundle install 或者 bundlebundle -v 都会提示
undefined method activate_bin_path for Gem:Module (NoMethodError)

然而却可以运行 bundler bundler -v

过程:试着 gem uninstall bundle 然后再 gem install bundle ,会提示安装成功,但症状依旧。

解决:google 到这个结果,按照最后一个答案

For me, (I am working with RVM) it worked just running:

gem update --system
gem update bundler

运行 gem update --system 就可以解决了,不需要后面一步。


用 navicat 导出 ER 图

google navicat 导出表结构
这个结果说的是导出SQL文件,不符合预期

google navicat 导出表结构图片
结果不理想

google navicat 结构图片
第一个结果是《用Navicat制作ER图及与SQL互相转化》,答案在里面:

将现成的数据库转换为ER图
选中已连接的数据库中 数据表——右键,选择“逆向数据库到模型”,即可根据现成的数据库生成ER图模型。


端口占用的解决方法:

  1. 终端中输入 sudo lsof -iTCP -sTCP:LISTEN -P | grep :3000
  2. 输入本机密码
  3. 终端中输入ruby后面的号码,假设是是16705,则: kill -9 16705

rake db 错误的解决办法

运行rake db:migrate 提示:

== 20160928075454 Users: migrating ============================================
-- add_column(:users, :user_name, :string)
rake aborted!
StandardError: An error has occurred, this and all later migrations canceled:

SQLite3::SQLException: no such table: users: ALTER TABLE "users" ADD "user_name" varchar

解决: rake db:schema:load


rails console 无法新增记录

输入Group.create(title: "Board 1", description: "Board 1 body"),提示

   (0.1ms)  begin transaction
   (0.1ms)  rollback transaction
 => #<Group id: nil, title: "Board 1", description: "Board 1 body", created_at: nil, updated_at: nil, user_id: nil>

 

原因在于 model 里将 user 和 group 的关系关联了起来,所以需要给 group 指定 user id 即可(当然前提是数据库里要存在这个 user ,不然也还是会报错)。

重新输入Group.create(title: "Board 1", description: "Board 1 body", user_id:"1")


Rails 相关笔记集合

  • rails c 只能在当前档案打开,是档案的后门

  • irb 可以在任何环境打开

  • git add . 尽量不要使用,只add想要的文件

  • git服务器可以自架,除了github,还有很多的git服务商

  • Rails最大的特点是有很多Gem套件

  • rubygems.org统一控制版本代码。

  • 比如 A 引用 B 的1.0,C 引用 B 的2.0 ,bundle 负责 gem 之间的相依性,放在 gemfile.lock里面,commit 的时候要把 gemfile.lock 也加入,远端服务器才能记录引用。

  • 密码不要上传到到GitHub,不要上传 config / database.yml ,为了保持目录结构,可以拷贝一份空的 databasy.sample.yml

  • 除了 .html.erb ,还有 .css.erb 之类的问件,它们可以混合使用 ruby 语法。

  • google rails validate,有很多的API

  • rake routes里面,:format可以生出不同的格式,比如.css .jason

  • ID可以自定义

  • collection 是一群,一群东西就不会有 id

  • member 是单个,就会有 id


如何自定义 Devise 的 controller

以修改devise的注册页面加入验证码为例:

  1. 在app中显示devise的controller
    rails g devise devise/users
    其中devise/users是scope值,可以自定义到其他位置

  2. 修改/app/controllers/devise/users/registrations_controller.rb

   def new
     super
   end

  def create
    if verify_rucaptcha?(params[:_rucaptcha])
      super
    else
      flash[:alert] = "验证码错误"
      redirect_to :back
    end
  end

这里面的if verify_rucaptcha?(params[:_rucaptcha])
是我们主要想要自定义的部分。
super是 devise 自己的方法。

3.修改/config/routes.rb

Rails.application.routes.draw do
  devise_for :users, :controllers => {:registrations => "devise/users/registrations"}

   略...
end

这里面的devise/users/registrations就是具体的要自定义的controller位置。


ruby 新语法

%i 是Ruby 2.0之后对Array 的一种简便写法,array 里面不同symbol用空格space隔开,
如%i(new create edit)

参考:http://ruby.zigzo.com/2014/08/21/rubys-notation/

%q[ ] # Non-interpolated String (except for \\ \[ and \])

%Q[ ] # Interpolated String (default)

%r[ ] # Interpolated Regexp (flags can appear after the closing delimiter)

%i[ ] # Non-interpolated Array of symbols, separated by whitespace

%I[ ] # Interpolated Array of symbols, separated by whitespace

%w[ ] # Non-interpolated Array of words, separated by whitespace

%W[ ] # Interpolated Array of words, separated by whitespace

%x[ ] # Interpolated shell command

修复 rails c 运行时提示 Reason: image not found readline.bundle

描述:运行 rails c ,提示Reason: image not found readline.bundle

判断:某个 app 的 gemfile 里面有安装 rb-readline 这个 gem ,不知道会不会有关系?但如果为了解决这个问题给所有的 rails 项目安装 rb-readline 显然是不合理的(其实应该先验证一下是不是会这样),毕竟人家原本没有这个 gem 是可以正常运行 rails c 的。

搜索:
google Reason: image not found readline.bundle
第一个结果没打开,我猜是因为看到搜索结果下面的日期是2012年9月25日。事后在回顾过程的时候发现里面说brew link readline --force就可以了。
打开第二个结果,里面有一个回答提供了两种解决方案:


brew update
brew uninstall readline
brew install readline

没有解决


rvm cleanup all
rvm autolibs enable
rvm install 2.1.0

还是没有解决
这时看到 rails 的 github 上有一个issues ,里面的错误跟自己的报错是一样的,解答如下。

works for me:
ln -s /usr/local/opt/readline/lib/libreadline.7.0.dylib /usr/local/opt/readline/lib/libreadline.6.dylib

这个是两行代码的意思吗?
第一行 ln -s /usr/local/opt/readline/lib/libreadline.7.0.dylib 能够运行,可第二行/usr/local/opt/readline/lib/libreadline.6.dylib感觉不太对,所以改成了ln -s /usr/local/opt/readline/lib/libreadline.6.dylib还是不对
(后来在使用 powder 的时候才知道 ln -s 是创建软连接的命令)
所以又回到之前 google 的第二个结果,里面的最高按照里面点赞最高的回答:


brew install readline ruby-build
env CONFIGURE_OPTS=--with-readline-dir=`brew --prefix readline` rbenv install 1.9.3-p286

这里面第一行可以用,
第二行的rbenv install 1.9.3-p286我改成brew install 2.3.1p112,即:

env CONFIGURE_OPTS=--with-readline-dir=`brew --prefix readline` brew install 2.3.1p112

因为我用 brew 而不是 rbenv 管理 ruby ,另外我的 ruby 版本是 2.3.1p112 ,现在回想参考的时候忘了加一个横杠,即2.3.1-p112。总当时这行命令没有起作用,然后又去掉了 p112 后缀,
改成:

env CONFIGURE_OPTS=--with-readline-dir=`brew --prefix readline` brew install 2.3.1

但还是不行。然后我就想,rails c 不可以运行,那 irb 可以运行吗?
试着运行了 irb ,能进入命令行,只是会提示:

Readline was unable to be required, if you need completion or history install readline then reinstall the ruby.

所以又试着去搜索上面的这个提示,按着某个答案的步骤走:
rvm pkg install readline
rvm reinstall all --force
在 reinstall 的最后会提示Unknown ruby interpreter version (do not know how to handle): .all。不过这个时候已经能正常进入 rials c 了。应该是rvm reinstall all解决的。

2016.11.1更新:后来有同学出现同样的问题,是用上文提到的ln -s /usr/local/opt/readline/lib/libreadline.7.0.dylib /usr/local/opt/readline/lib/libreadline.6.dylib解决的。记住,这个是一行命令而不是两行……


bundle 的时候提示 git protocol

运行 bundle config git.allow_insecure true 即可


bundle 的时候提示 Failed to build gem native extension.

运行 gem install capybara-webkit -v '1.11.1' 即可


安装 capybara-webkit 的时候提示 qmake: command not found

运行 brew install qt ,安装 Qt
安装完成之后重新运行 gem install capybara-webkit -v '1.11.1' 就能正常安装 gem 了,然后再 bundle install


bin/test 提示 gem 版本需要更新

运行 bundle update


在 atom 里使用 command + p 快速打开文件时一直显示 Indexing project (0)。

在其他项目,可以使用 command + p ,说明 atom 本身设置没问题。
退出 atom ,重新运行并打开 rails 项目,就可以正常使用 command + p 了。

TED 演讲《出人意料的工作动机》摘录

在规则简单、目标明显的情况下进行奖励,会让我们集中精神、变得专注,这便是为何奖励在许多情况下有效的缘故。

但在真正的“蜡烛问题”中,我们需要四处寻找解答,而奖励却令我们眼光狭隘,限制了我们的想象力。

科学知识和商业行为之间有条鸿沟

一、奖励只在特定的情况下有用;
二、奖励往往会破坏创造力;
三、高绩效的秘密不是奖励和惩罚,而是看不见的内在动力。


研究人类动机的科学家已经给了我们一个新方向——这个新方向讲求内在的诱因——我们想做是因为它能改变世界、因为我们喜欢、因为它很有趣、因为它能影响的范围很广。

新商业机制的三个基础

1.自主性——想要主掌自己人生的需求;
2.掌握力——想要在举足轻重的事情上做得更好的欲望;
3.使命感——希望我们所做的事情是为了更高远的理想的渴望。

案例1

澳大利亚 Atlassian 软件公司跟自己的软件工程师说 “接下来的24个小时,去做你自己想做的事,只要它和你每天的工作无关,随便你要做什么都行。” 在高度自主的24小时里,这些工程师做出了许多之前根本没人想到的软件编程的革新。

案例2

只论结果的工作环境(简写 ROWE )。由两个美国分析师所创造,用在十多家北美公司上,在 ROWE 之中,人们没有日程表,他们想来就来,他们不需要在特定时间到公司,他们只需要把工作完成,怎么做、何时做、在哪里做,都取决于他们自己,甚至连开会都是选择性的,结果呢?几乎所有公司的生产力都提升了:工作投入度提升、工作满意度提升、人力流失降低。

案例3

90年代中期,微软开始了一个叫做 Encarta 的百科全书计划,他们使用了所有正确的诱因,他们付钱给专业人士撰写和编辑文章,收入颇丰的主管们监督着整个计划,确定它不会超过预算和时间。几年后,Wikipedia 开始了完全不同的免费模式,没有人能从中拿到任何一毛钱,人们完全为了兴趣而作(潜台词:Encarta 没了下文,Wikipedia 却越发壮大)。


点此查看 TED 原视频

延伸阅读:为你做的事赋予意义