页面采用响应式布局可以在移动设备上有较好的展现效果,但移动设备输入长长的URL地址有些麻烦。URL二维码结合微信扫一扫可以较好的解决输入不便的问题。通常二维码是一张黑白相间的图片,网上可以找到很多二维码的生成工具和生成服务。所以二维码通常采用预生成或者临时请求第三方服务生成的方式引入到页面中,本文介绍一种通过js动态生成二维码的实现方法,并附带交互上的特效。动态生成可以方便的适应URL的变化。js动态生成可以去除对第三方服务的依赖,在隔绝内网下也可以使用。

页面二维码效果图

继续阅读 →

Capistrano发布Rails app到远端服务器时,只在primary db服务器上执行db:migrate。对于每个app都使用独立的本地Sqlite数据库的场景不适用。

通过添加如下task,在每台app服务器上执行db:migrate

#lib/capistrano/task/migrate_all.rake

desc 'Runs rake db:migrate on all app server'
task :migrate_all => [:set_rails_env] do
	on roles(:app), in: :parallel do
		within release_path do
			with rails_env: fetch(:rails_env) do
				execute :rake, "db:migrate"
			end
		end
	end
end

after :updated, :migrate_all

一对Master-Agent模式Rails应用,Agent需要验证Master。通常考虑采用HTTP基础认证或者HTTP摘要认证。这里Agent不需要多用户支持,所以只要一个加密口令即可,无需用户名。本文介绍采用JWT实现基于Token验证,结合Rails 4.1的新特性,装载secrets.yml文件里的密钥,作为JWT Token的计算密钥,应用于Rails应用。

Agent端配置

安装jwt Gem

Gemfile添加如下行

gem 'jwt'

然后执行bundle install

继续阅读 →

应用的版本管理和代码的版本管理通常是分开的,作为两套独立的版本系统来维护。对于小型应用来说有些浪费精力。最早在GitLab这款开源软件上看到其使用Git的提交版本号作为版本号,本文将借鉴这种做法。

获得Git版本号

  1. 开发环境,当前的工作目录里包含了.git目录,直接执行下面的命令git describe --always。该命令通常返回形如1f36a3b的SHA-1短序列,但是如果该提交版本有对应的Tag的话,将返回该Tag名称。真实应用发布场景显得非常有用,毕竟随机序列不如自定义的有意义的名称便于记忆、沟通和传播。
  2. 对于Capistrano工具发布的生产环境,应用根目录不包含.git目录,所以如果通过git命令直接获得代码版本号,好在Capistrano发布时会自动生成REVISION文件,其内容为代码版本号。

综合两种情况的代码如下

if File.exist? 'REVISION' then `cat REVISION`.chomp else `git describe --always` end
继续阅读 →

OpenID解决跨站点的认证问题,OAuth解决跨站点的授权问题。认证和授权是密不可分的。而OpenID和OAuth这两套协议出自两个不同的组织,协议上有相似和重合的之处,所以想将二者整合有些难度。好在OpenID Connect作为OpenID的下一版本,在OAuth 2.0的协议基础上进行扩展,很好的解决了认证和授权的统一,给开发者带来的便利。在学习和研究OpenID Connect协议时,遇上两个概念基于Token的认证(token based authentication)和基于声明的标识(claims based identity)。本文就这两个概念展开讨论,为了更好的理解OpenID Connect协议的原理。

基于Cookie的认证和基于Token的认证

有两种不同的方法实现服务端的认证

  • 常见方式是基于Cookie的认证,每个请求中携带Cookie信息以便于服务端识别
  • 另一种新方法,基于Token的认证,在每个请求中携带被签名过Token信息传送到服务端

Cookie-based Auth vs Token-based Auth

继续阅读 →

泛型典型的使用场景是集合。考虑到大多数情况下集合是同质的(同一类型),通过声明参数类型,可免去类型转换的麻烦。本文将讨论本人阅读Spring Security源码时遇到的一个关于泛型递归模式的问题。

声明方法返回子类型

在Spring Security的源码里有一个ProviderManagerBuilder接口,声明如下

public interface ProviderManagerBuilder<B extends ProviderManagerBuilder<B>> extends SecurityBuilder<AuthenticationManager> {
    B authenticationProvider(AuthenticationProvider authenticationProvider);
}

其实现类AuthenticationManagerBuilder

public class AuthenticationManagerBuilder extends AbstractConfiguredSecurityBuilder<AuthenticationManager, AuthenticationManagerBuilder> implements ProviderManagerBuilder<AuthenticationManagerBuilder> {

    //...
    
	public AuthenticationManagerBuilder authenticationProvider(
        AuthenticationProvider authenticationProvider) {
    	this.authenticationProviders.add(authenticationProvider);
    	return this;
	}
	
    //...

}

上面有很多干扰项,我们来简化一下

继续阅读 →

没有系统的学习过关系数据库,所以对SQL Select的理解有些浅薄,特别是group by和having语句。《SQLite 权威指南(第二版)》的第三章SQLite中的SQL,让我对Select,乃至SQL语言和关系数据库有了全新的认识。一时间激起了对关系数据库和理论的兴趣,到豆瓣上淘了一本绝版的《深度探索关系数据库》,可惜基础太差,读了一半实在读不下去了,作罢。

最大的收获和发现莫过于下面这幅图了,

select处理过程

继续阅读 →

由于国内网络原因(你懂的),导致rubygems.org存放在Amazon S3上面的资源文件间歇性连接失败。所有你会遇到gem install rackbundle install的时候半天没有响应。将默认源改成国内的淘宝源(http://ruby.taobao.org)可以解决该问题。

对于Rails项目通常需要将Gemfile的第一行改为

	source 'http://ruby.taobao.org/'

但是通过rails new my_project创建项目时,由于Gemfile生成以后立即执行bundle install,此时source尚未修改,所以项目创建的过程仍然很慢。

解决rails new 卡住的问题,有如下两种方法

继续阅读 →

MacBookAir的SSD坏了两次以后,发现TimeMachine真的很有必要。外插个尿袋子真的不方便。AirPort Time Capsule 2T版本价格买到了$299,觉得有些不值。$25的树莓派+一块移动硬盘DIY一个Time Capsule即经济又有趣。

Raspberry Pi as TimeCapsule

继续阅读 →

感谢刘博士送的这块pcDuino板。入Raspberry Pi前,优先考虑过pcDuino。在OSChina源创会上海站被刘博士打动过。买Raspberry Pi是为了DIY一个Mac的Time Capsule。随便Google了一下,找到了Raspberry实现Time Capsule的相关资料,而pcDuino的相关资料没有找到,于是作罢。

pcDuino V2

由于Raspberry Pi的先入为主,上手pcDuino碰到写问题,下面一一列出

继续阅读 →