mac下rails项目连接oracle数据库

最近上了一个新项目,需要用oracle数据库,oracle数据库对mac的支持太弱了。本来想在本地装一个oracle数据库,但是mac竟然没有11g版本的oracle,因为生产环境用的是oracle 11g,所以就放弃了在本地装oracle的。然后直接连的测试机的oralce。rails用oracle相比用mysql来说,也复杂了很多。

1.首先,需要去官网下载oracle client,linux基本一致,找到对应自己版本的client下载即可。一共需要下载3个文件。

rails发送邮件 smtp qq

rails中使用邮件服务是非常方便的,直接加配置文件就可以,但是配置的时候很多时候会有问题,无法看到具体的报错信息,这里记录下qq smtp的踩坑过程。

production.rb需要添加如下配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
ActionMailer::Base.delivery_method = :smtp
config.action_mailer.perform_deliveries = true
config.action_mailer.raise_delivery_errors = true
config.action_mailer.default :charset => "utf-8"
ActionMailer::Base.smtp_settings = {
:address => 'smtp.qq.com',
:port => 465,
:domain => 'qq.com',
:user_name => 'xxx@qq.com',
:password => 'xxxxxxxxx',
:authentication => 'plain',
:ssl => true,
:enable_starttls_auto => true
}

切记,qq邮箱后台要开启POP3/SMTP服务,开启的时候需要通过发送短信息启用,启用的时候会生成一个授权码,配置文件的password只需要填写授权码即可。

rails_devise_warden_登陆解析

devise是rails用的比较多的一个用户登陆注册模块,研究了下他的登陆以及验证的策略(虽说还没有完全吃透),先记录下。
devise的具体使用可以参照他的文档
devise的认证机制是基于warden,所以要先了解一下warden才能理解。用户名以及密码的验证我们这里暂且不提,主要看一下sign_in方法做了什么,以及登陆之后下次请求是如何把已登录的信息带过来验证的。
1.先看下sign_in方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
def sign_in(resource_or_scope, *args)
options = args.extract_options!
scope = Devise::Mapping.find_scope!(resource_or_scope)
resource = args.last || resource_or_scope
expire_data_after_sign_in!
if options[:bypass]
warden.session_serializer.store(resource, scope)
elsif warden.user(scope) == resource && !options.delete(:force)
# Do nothing. User already signed in and we are not forcing it.
true
else
warden.set_user(resource, options.merge!(scope: scope))
end
end

warden.session.store方法,会把user id存入env[‘rack.session’][‘warden.user.user.key’]中

1
2
3
4
5
6
7
8
9
10
11
12
13
# gems/warden-1.2.3/lib/warden/session_serializer.rb
def store(user, scope)
return unless user
method_name = "#{scope}_serialize"
specialized = respond_to?(method_name)
session[key_for(scope)] = specialized ? send(method_name, user) : serialize(user)
end
#gems/warden-1.2.3/lib/warden/manager.rb
def serialize_into_session(scope = nil, &block)
method_name = scope.nil? ? :serialize : "#{scope}_serialize"
Warden::SessionSerializer.send :define_method, method_name, &block
end

2.已登陆成功之后,通过authenticate_user! 来验证是否登陆

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
def self.define_helpers(mapping) #:nodoc:
mapping = mapping.name
class_eval <<-METHODS, __FILE__, __LINE__ + 1
def authenticate_#{mapping}!(opts={})
opts[:scope] = :#{mapping}
warden.authenticate!(opts) if !devise_controller? || opts.delete(:force)
end
def #{mapping}_signed_in?
!!current_#{mapping}
end
def current_#{mapping}
@current_#{mapping} ||= warden.authenticate(scope: :#{mapping})
end
def #{mapping}_session
current_#{mapping} && warden.session(:#{mapping})
end
METHODS
ActiveSupport.on_load(:action_controller) do
helper_method "current_#{mapping}", "#{mapping}_signed_in?", "#{mapping}_session"
end
end
#["/Users/.rvm/gems/ruby-2.3.0/gems/warden-1.2.3/lib/warden/proxy.rb", 103]
[查看此文件可知](https://github.com/hassox/warden/blob/master/lib/warden/proxy.rb)最后是通过获取env["rack.session"]['warden.user.user.key']来获取到当前登陆的用户的

Tips:

查看一个方法调用的位置:

method(:sign_in)
# ["/Users/.rvm/gems/ruby-2.3.0/gems/devise-3.4.1/lib/devise/controllers/sign_in_out.rb", 30]
warden.session_serializer.method(:store).source_location
# ["/Users/.rvm/gems/ruby-2.3.0/gems/warden-1.2.3/lib/warden/session_serializer.rb", 22]

参考文档

warden wiki
warden源码解析
rack中间件warden的机制
rack安全

rails_import_xls_and_csv

项目中经常会遇到需要导入excel以及csv等文件格式的数据到数据库中。
1.导入xls文件,文档
添加gem

1
gem 'spreadsheet', '1.0.0'

导入的只能是xls格式的,如果为xlsx格式的需要先手动转化为xls格式在进行导入,直接在rails c 中读取文件,然后操作

1
2
3
4
5
book = Spreadsheet.open('public/a.xls'); #如果是在rails c中直接读取的时候,最后记得加上分号,如果不加分号会全部读取,要等很长时间
sheet = book.worksheet 0 #后面的数字是代表读取那个工作区间的
sheet.each_with_index do |row, index|
p row[0] #index为行数 row为具体行里的内容,row[0]指的是取出第一列
end

2.导出xls文件

1
2
3
4
5
6
7
8
xls_report = StringIO.new
Spreadsheet.client_encoding = 'UTF-8'
book = Spreadsheet::Workbook.new
sheet1 = book.create_worksheet name: '测试' #工作区
sheet1.row(0).concat([第一列,第二列])
sheet1[1,0] = 'china'
sheet1.column(0).default_format = Spreadsheet::Format.new align: :right,weight: :bold #局右加粗
book.write xls_report #保存