系统环境:

  • Ruby: ruby 2.5.1p57 (2018-03-29 revision 63029) [x86_64-linux]
  • Rails: Rails 5.2.2
  • Gem: 2.7.7
  • SQLite: sqlite3 (1.4.0, 1.3.13)

今天在基于上面的环境使用Rails新建项目的时候,报了一个ActiveRecord::ConnectionNotEstablished错误。
根据排查,是由于SQLite3 gem版本问题导致的。
具体的报错内容如下:

1
Puma caught this error: Error loading the 'sqlite3' Active Record adapter. Missing a gem it depends on? can't activate sqlite3 (~> 1.3.6), already activated sqlite3-1.4.0. Make sure all dependencies are added to Gemfile. (LoadError)

页面报错如下:

1
2
ActiveRecord::ConnectionNotEstablished
No connection pool with 'primary' found.

后来找到了解决方法,修改Gemfile,将sqlite3的版本降级到1.4.0以下即可。
修改Gemfile:

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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
source 'https://rubygems.org'
git_source(:github) { |repo| "https://github.com/#{repo}.git" }

ruby '2.5.1'

# Bundle edge Rails instead: gem 'rails', github: 'rails/rails'
gem 'rails', '~> 5.2.2'
# Use sqlite3 as the database for Active Record
gem 'sqlite3', '< 1.4.0' # <<修改这里,将sqlite3版本设定为小于1.4.0
# Use Puma as the app server
gem 'puma', '~> 3.11'
# Use SCSS for stylesheets
gem 'sass-rails', '~> 5.0'
# Use Uglifier as compressor for JavaScript assets
gem 'uglifier', '>= 1.3.0'
# See https://github.com/rails/execjs#readme for more supported runtimes
# gem 'mini_racer', platforms: :ruby

# Use CoffeeScript for .coffee assets and views
gem 'coffee-rails', '~> 4.2'
# Turbolinks makes navigating your web application faster. Read more: https://github.com/turbolinks/turbolinks
gem 'turbolinks', '~> 5'
# Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder
gem 'jbuilder', '~> 2.5'
# Use Redis adapter to run Action Cable in production
# gem 'redis', '~> 4.0'
# Use ActiveModel has_secure_password
# gem 'bcrypt', '~> 3.1.7'

# Use ActiveStorage variant
# gem 'mini_magick', '~> 4.8'

# Use Capistrano for deployment
# gem 'capistrano-rails', group: :development

# Reduces boot times through caching; required in config/boot.rb
gem 'bootsnap', '>= 1.1.0', require: false

group :development, :test do
# Call 'byebug' anywhere in the code to stop execution and get a debugger console
gem 'byebug', platforms: [:mri, :mingw, :x64_mingw]
end

group :development do
# Access an interactive console on exception pages or by calling 'console' anywhere in the code.
gem 'web-console', '>= 3.3.0'
gem 'listen', '>= 3.0.5', '< 3.2'
# Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring
gem 'spring'
gem 'spring-watcher-listen', '~> 2.0.0'
end

group :test do
# Adds support for Capybara system testing and selenium driver
gem 'capybara', '>= 2.15'
gem 'selenium-webdriver'
# Easy installation and use of chromedriver to run system tests with Chrome
gem 'chromedriver-helper'
end

# Windows does not include zoneinfo files, so bundle the tzinfo-data gem
gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby]

修改完后执行bundle即可。



你在MongoDB启动时也遇到以下警告吗?

1
2
3
WARNING: You are running on a NUMA machine.
We suggest launching mongod like this to avoid performance problems:
numactl –interleave=all mongod [other options]

这是当MongoDB运行在非统一内存访问架构 NUMA(Non Uniform Memory Access Architecture)下产生的性能告警。
关于NUMA是什么,可以参考这篇文章:Non-uniform memory access

这里主要提一下在CentOS 7系统、NUMA架构服务器中上述告警该如何消除。

首先需要使用numactl这个命令,而这条命令服务器中默认是没有的,在支持NUMA架构的CentOS7服务器中,可以运行yum install numactl来安装它。

接着关闭MongoDB服务:
systemctl stop mongod

disable掉MongoDB服务的自动启动:
systemctl disable mongod

使用numactl来启动MongoDB:
numactl --interleave=all mongod --config /etc/mongod.conf

如果想要开机自动使用numactl启动MongoDB,将上述命令写到开机启动的脚本文件中即可。

笔者尝试修改mongod.service服务描述中的ExecStart选项,尝试将numctl作为mongod服务的执行体时报了很多错,如果你有相关的解决方法,欢迎来信或在评论里探讨。



笔者有一台CentOS 7系统的Linux服务器,在通过ssh远程连接的时候,一直存在两个问题。
一是连通速度缓慢,ping服务器速度很快,但是SSH连接的响应非常慢。
再有就是连接一段时间,客户端这边如果没有操作和输入,服务器就会自动断开,每次都要重新连,很麻烦。

昨天晚上仔细检查了一下CentOS 7 sshd的配置,终于解决了这两个问题。其实很easy,修改CentOS默认的sshd配置就行了。

针对第一个ssh连接响应缓慢的问题,在/etc/passwd文件里这样配置就行了:

大概是在第129行的位置,找到UseDNS选项,取消前面的注释,将yes改为no即可:

1
2
3
4
5
6
7
127 #ClientAliveCountMax 3
128 #ShowPatchLevel no
129 UseDNS no
130 #PidFile /var/run/sshd.pid
131 #MaxStartups 10:30:100
132 #PermitTunnel no
133 #ChrootDirectory none

针对第二个连接超时timeout的问题,同样是修改sshd配置,大概在第126行的位置,找到选项ClientAliveInterval,将其值修改为30:

1
2
3
4
5
6
123 UsePrivilegeSeparation sandbox          # Default for new installations.
124 #PermitUserEnvironment no
125 #Compression delayed
126 ClientAliveInterval 30
127 #ClientAliveCountMax 3
128 #ShowPatchLevel no

这样ssh服务器就会每隔30秒判断一次客户端是否超时,由于30秒一般是不会超时的,所以连接就能持续。
而第127行的选项也可以关注一下,它代表的是最大的超时次数。

完美修复文章开头提到的两个问题。



一、巢湖

乙亥年正月初六午后,动身回宁。
驱车至合安高速入口,进错车道,于是原本打算途径合肥的路线,临时改成先至马鞍山再北上。沿途一路雪景,甚是秀美。沿着省道过了巢湖,就来到了安徽的含山县。谁知大雪封路,高速不得上,只得在交警的指挥下改道。于是重新探路,在那含山县城乱转悠。此时汽油已经不多了,只能勉强再行个两百里。人生地不孰,一路留意着苏A牌照的车,想着最好遇个返程的老司机带路,免得找错。先是遇到个雪佛兰,那哥们和我一样,也是被警察叔叔拦着不让上高速的,等红灯的时候跟他聊了几句,听他说走和县,沿小路到马鞍山。我心里也差不多是这个思路,于是一脚油门先溜了。
走了不久就走错了路,含山县里多处修路、封路,找路很困难,偏偏车机这个时候也没什么信号。过了一会凭着感觉从拐错的路口绕了出来,过了个红灯以后,遇到一辆市区出租车,上前打了个招呼,问他是不是回南京,师傅人很好,直接说,你跟着我走吧。于是一起很省心的开了一段,车机信号这个时候恢复了,但是都没怎么看导航。老师傅就是老师傅,一路节奏带的飞起,好几段堵成深红色的路段,跟着他从加油站、小道绕路,足足节省了至少四十分钟!
中途有一个实在很堵的点,老师傅也过不去了,停下来观望,拿着电动剃须刀站在车外剃起了胡子。我带了包玉溪烟下车,他摆摆手说不抽。聊了聊路况和导航,他问我用的什么,我说腾讯地图,他说换高德,等下一起从乌江到江浦,过了长江大桥就到了。后来我下了一个高德,用起来其实差不多,反而林志玲的声音不如腾讯地图里的妲己。中间因为下载高德地图,跟丢了老师傅,我就一路自己开着两个导航,仪表盘上显示只能开90公里了。
路过一个国道上的石化加油站,去补充汽油,在加油站的洗手间里竟又遇到了老师傅。心想这回真是巧了,就打了个招呼,他说加个微信,等下他在前面开,让我不认识路就呼他,他可能以为我一直在后面跟着。加了微信,他还把我的会话置顶了,贴心啊。他说微信昵称是他法号,是位道教信徒。我表示对道家思想也挺有兴趣的,回南京有机会一起交流。

二、乌江

从含山继续出发,一路上和道友老师傅用微信简短地讨论了路况。一个小时左右,便到了和县乌江。
想到这曾是西楚霸王项羽自刎的地方,不禁唏嘘。
当年霸王被刘邦围困垓下,带领八百将士突围至此,夜半帐中楚歌四起,军心涣散,虞姬也先抹剑而去。为了面子,为了证明自己“不是不会打仗”,而是“天要亡我”,霸王带着必死的决心亲自迎斩敌将,吓的围军丧胆,也让一众部下服了最后一口气。但最终损员折将,失了兵马,身负重伤。因为面子而出战的人,也要为了面子而赴死,
其实何为天道?何为颜面?既信了天道,又怎谓人言?只怕是输在了心态。否则克制一时的崩溃渡到江东,江东富饶广阔,又有天险阻隔。刘邦阻击项羽,兵力早已残损。更有支持自己的江东子弟,一呼百应。无论如何都值得再去拼他一次。已经在沙场上失去了身旁的战友,又在帐中告别了心爱的女人,还有什么可以失去的呢?还有什么是害怕失去的呢。后人每当想起这位刚愎自用,却又威武神勇的霸王,都常常替他惋惜。李清照诗云:

生当作人杰,死亦为鬼雄。
至今思项羽,不肯过江东。

从历史角度看,项羽听信谗言,疏远了得力又忠心的老臣范增,就是他最终将会失败的一个前兆。《史记·高祖本纪》中记载,刘邦曾经如此评价项羽:”项羽有一范增而不能用,此其所以为我擒也。”。在昔日的对手眼里,即使世人视为神勇的霸王,也不过只是一个必须拔除的障碍罢了。
说到刘邦,就不得不说,项羽屡次亲自挑战,刘邦从不正面回应。项甚至摆下鸿门宴以图杀之,却依然让放低姿态的刘邦,骑着白马,借口脱逃。鸿门宴时项羽有范增、项庄,献计舞剑,沛公亦有樊哙、张良,鞍前马后,莫论成功与否,成事一定离不开用臣。自古先贤们的智慧碰撞揭示着人性的真相,小人沟通乃至大国邦交,谁能没有胸襟跟视野、谋略和手段、演技与心肠呢。
路过乌江时天色已晚,穿过乌江地域,便穿过了苏皖两地的交界,从和县到了江浦,渡过长江,即至金陵。

三、后记

傍晚开车请注意:道路千万条,安全第一条。行车不规范,钱包两行泪。



庆幸有这一片幽谷得以避世,有这一座空山可以守寂。

信步闲庭,纵情山水。

逆旅徒行,万物大千皆是过客。

喧嚣与纷扰,尘埃落定。繁华和落寞,过眼云烟。

令人亦步亦趋的,是这匆匆的旅途,浮沉起落之间。

令人沉醉又着迷的,是这人生的时光,如同白驹过隙。

那些刹那又永恒的幸福,纯粹的喜悦。

那些短暂的相聚,相聚又离别。



Python 3 通过SMTP库发送普通邮件(Through SSL)

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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
#!/usr/bin/python3

import smtplib
from email.header import Header
from email.mime.text import MIMEText
from email.mime.image import MIMEImage
from email.mime.multipart import MIMEMultipart

mail_host = "smtp.chorder.net"
mail_port = 994
mail_user = "example@chorder.net"
mail_pass = "password"

sender_name = "Example"
sender_account = 'example@chorder.net'
receivers = ['someboby@chorder.net']
receiver_name = "Somebody"

subject = 'Mail Subject'
mail_msg = '''
<h1>This is a test main</h1>
<p>Some text</p>
'''


msgRoot = MIMEMultipart('related')
msgRoot['From'] = Header(sender_name, 'utf-8')
msgRoot['To'] = Header(receiver_name, 'utf-8')
msgRoot['Subject'] = Header(subject, 'utf-8')

msgAlternative = MIMEMultipart('alternative')
msgAlternative.attach(MIMEText(mail_msg, 'html', 'utf-8'))

msgRoot.attach(msgAlternative)

try:
smtpObj = smtplib.SMTP_SSL( mail_host, mail_port )
#smtpObj.ehlo()
#smtpObj.set_debuglevel(1)
smtpObj.login( mail_user, mail_pass )
smtpObj.sendmail(sender_account, receivers, msgRoot.as_string())
print ("邮件发送成功")
except smtplib.SMTPException:
print ("Error: 无法发送邮件")

Python 3 通过SMTP库发送带图片的邮件(Through SSL)

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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
#!/usr/bin/python3

import smtplib
from email.header import Header
from email.mime.text import MIMEText
from email.mime.image import MIMEImage
from email.mime.multipart import MIMEMultipart

mail_host = "smtp.chorder.net"
mail_port = 994
mail_user = "example@chorder.net"
mail_pass = "password"

sender_name = "Example"
sender_account = 'example@chorder.net'
receivers = ['someboby@chorder.net']
receiver_name = "Somebody"


subject = 'Mail Subject'
mail_msg = '''
<h1>This is a test main</h1>
<p>Some text</p>
<h2>Image</h2>
<p><img src="cid:image1"></p>
'''

# add image attachment
fp = open('test.png', 'rb')
msgImage = MIMEImage(fp.read())
fp.close()

msgImage.add_header('Content-ID', '<image1>')

msgRoot = MIMEMultipart('related')

msgRoot['From'] = Header(sender_name, 'utf-8')
msgRoot['To'] = Header(receiver_name, 'utf-8')
msgRoot['Subject'] = Header(subject, 'utf-8')

msgAlternative = MIMEMultipart('alternative')
msgAlternative.attach(MIMEText(mail_msg, 'html', 'utf-8'))

msgRoot.attach(msgAlternative)
msgRoot.attach(msgImage)

try:
smtpObj = smtplib.SMTP_SSL( mail_host, mail_port )
#smtpObj.ehlo()
#smtpObj.set_debuglevel(1)
smtpObj.login( mail_user, mail_pass )
smtpObj.sendmail(sender_account, receivers, msgRoot.as_string())
print ("邮件发送成功")
except smtplib.SMTPException:
print ("Error: 无法发送邮件")


岁数越来越大,感觉所了解的做人的道理却越来越少。

生活复杂吗?生活需要纠缠于种种变化,需要交织于变化之中的人们。

变化无穷无尽,烦恼亦无穷无尽。

确定性让我们对生活能够精确把握,而在变化中,如何寻找一种确定性?

那就是要遵循生存的法则,坚持做人的原则。

原则不是顽固与执着,原则是生长的基础,是生存的边界。

原则能让事物变得简单,能让自己和身边的人睡得踏实。

原则不与清高相矛盾,原则只是界定了虚伪。

原则让自己不费脑筋,也让别人少伤脑筋。



Docker镜像仓库在国内访问速度巨慢无比,感谢DaoCloud公司提供的稳定加速
镜像,具体的配置方法如下:

1. 修改 /etc/docker 目录下的daemon.json

如果没有/etc/docker这个目录或者/etc/docker目录下没有daemon.json文件,手动创建即可。
将daemon.json的内容修改如下:

1
2
3
{
"registry-mirrors": ["http://f1361db2.m.daocloud.io"]
}

2. 重启Docker服务

运行这两个命令:

1
2
systemctl daemon-reload
systemctl restart docker


Ruby有着便捷强大的Gem包管理机制,作为五十年后人类使用最多的编程语言,有必要提前普及一下Ruby Gem的编写制作教程,帮助大家更好的使用Ruby,使用Gem,最好也能让Ruby的Gem库更加丰富,社区能够更加活跃。那么如何从零开始制作和发布自己的Gem呢?一起来动手操作一下。

制作和发布Ruby Gem包一共分如下几个步骤:

  1. 在RubyGems上注册帐号(如果你只想在本地或团队内部使用你的Gem,可以跳过这一步)
  2. 编写和打包Gem(gem build xxx.gemspec)
  3. 测试Gem(mang自mu信者可以跳过这一步)
  4. 发布Gem(gem push xxx)

1. 注册RubyGems帐号

RubyGems.ORG 是一个大型的Gems仓库,你可以现在就加入它,贡献你的Gem。这一步想必无需多说,注册完成之后,你就拥有了属于自己的RubyGems帐号,别人就可以看到你的主页和你发布的Gems。

注册完成之后,你还需要将你的crendentials保存到本地,方便后续直接在命令行使用gem命令。运行

1
curl -u 你的用户名 https://rubygems.org/api/v1/api_key.yaml > ~/.gem/credentials; chmod 0600 ~/.gem/credentials

2. 编写和打包Gem

编写Gem

我们这次要发布的Gem叫做template_chorder,你也可以改名成任意你想要的名字。首先我们创建一个工程目录,我的目录名叫做GemTemplate,其中包含如下内容:

其中,template.gemspec是项目的描述文件,gem build命令会基于这个文件进行打包。

template.gemspec内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13

Gem::Specification.new do |s|
s.name = 'template_chorder'
s.version = '0.0.0'
s.date = '2019-01-11'
s.summary = "Template!"
s.description = "A simple template gem"
s.authors = ["Chorder"]
s.email = 'chorder@chorder.net'
s.files = ["lib/template.rb"]
s.homepage = 'https://chorder.net/2019/01/11/rubygemtemplate/'
s.license = 'MIT'
end

其中s.name就是将来这个包发布出去的名字。默认的,我们需要将工程的主代码放在lib目录里面,这是ruby的约定。我们的Gem只包含一个很简单的功能,只需要放置全部代码在一个文件当中即可。

lib/template.rb的代码如下:

1
2
3
4
5
class Template
def self.test
puts "Hello, Ruby!"
end
end

就是这么简单。

打包Gem

在工程的根目录,运行

1
gem build template.gemspec

工程根目录将会产生一个 template_chorder-0.0.0.gem文件。
就是这么简单。

3. 测试Gem

对于刚刚生成的template_chorder-0.0.0.gem,运行

1
gem install template_chorder-0.0.0.gem

来安装它。

安装好以后,就可以在irb解释器中引入和运行它了。完整的过程如下:

疑问
这里其实是有点疑问的,就是为什么gem的名字叫做template_chorder,而在irb中引入的却是template。确实,如果gem包中的文件取名不严谨的话,可能会与其他包产生冲突。至于如何消除冲突,请君自己先思考下。

卸载Gem包,运行 gem uninstall template_chorder

2. 发布Gem

制作好这样一个不负责任的Gem包以后,就可以厚颜无耻地在RubyGems上发布它。但是为了社区的环境卫生清洁,尽量还是不要发布那些粗制滥造的包,就以此为戒吧。
发布Gem包,运行 gem push template_chorder-0.0.0.gem,如果第1步当中的帐号注册和保存
crendentials文件都没有问题,那么包就可以发布出去了。

本文的包发布在:https://rubygems.org/gems/template_chorder

希望能够对你有所帮助。



又到了一年的末尾,自来南京以后,常常满怀仪式感地做某些事。像是每年一度的登栖霞山,以及每年一度的汤山,不定期去看长江,几年一度的登钟山。

今日又去了汤山。汤山位于南京的东郊,据说此地温泉极妙,蒋介石曾经在此整了个疗养院。如今的汤山,满满的商业气息。每至元旦,南方的天气湿冷,老中青成群结队来此中嬉戏。

此温泉我已经连续踏足过三届,每年都是和不同的人。去年是和大学舍友一起在元旦节当天去的。如今2018已经落幕,个人经验是元旦还是尽量不要去泡汤,元旦泡了汤的我的2018年,干什么黄什么。

这次去汤山,感觉人流量少了很多,上次去的时候,地下车库和地面上停了不少车,小杨生煎的队一直排到了门外,连吃口饭都困难。今天的小杨生煎,店铺里只坐了一半的人。与友笑道,莫非是消费真的降级了?连汤都不泡了吗。其实也有可能是,消费升级了,人们都去了更高大上的地方玩耍,只有我们这些LowB还继续流连这里,乐此不疲。

看到温泉的一处亭子上写着一副对联,下阕是“洗身容易洗心难”。我不太想说话。

年底了,总是有各种各样的新闻出来占据我们的视野。吴小波这两天又出来预测明年的经济。朋友圈各路人才对他褒贬不一,有的赞扬有的鄙视。而我觉得他书写的还算中肯,别的不了解,也不评论。

贸易战是要继续打下去的,本世纪异彩纷呈。昨天看了iPhone XR,居然连个3D touch都不带,老乔走了以后库克真是魅了良心。我作为无产阶级恐怕以后只能站在华为这一边。

明年,就是毕业第三个年头了!看看如今的自己,真的是不太满意啊。生命真的太无可奈何,太短暂了,我们甚至都没有足够的时间去好好感受它。以前总梦想自己在各个领域里牛逼,如今甚至觉得,能在一个领域里做出点成绩就已经很对得起这一辈子了。也许很多时候幸福来源于成就感,而成就在外界看来有大有小,有的人穷尽一生作出了一点客观上看起来很微小的成就,可是只要对于生命而言足够精彩,那就足够了。

就像是新闻里拾荒者攒钱赞助贫困大学生的例子,也许他用尽一生攒下的钱,还不如很多人买过的iPhone加起来的钱多,而他的一生,可能要比大多数拥有iPhone的人要精彩。那种用一辈子时间捡破烂,帮助很多人所获得的幸福和成就感,却是我们买iPhone所体会不到的。那种幸福感,可能就叫做信念吧。

今年,从年初就告诉自己,对自己要求少一点,本命年不宜大动,可还是跳了一次槽,搬了两次家。今年给自己的要求就是,花一年时间停一停,听一听自己内心的声音,搞清楚自己想要什么。搞清楚孰可为,孰不可为。就这样昏昏浑浑混了一年以后,其实多少算是想明白一些了。

跟有的人需要在一次很远的旅行中才想明白很多道理相比,我不同,我穷,所以不需要旅行就能想的很明白。

至于想明白什么,其实就是明白了舍弃,不能又想要熊掌,又想熊不想要你的手掌。

明白了人生短暂,光阴似箭,做自己想要做的事情,自己觉得对的事情,不要浪费时间。

要尽到做人、做儿子、做男人应尽的责任。

今日的汤山一行,沐浴过后,算是给过去的自己一个终结,给未来的自己一个新的开始。

悟已往之不谏,知来者之可追。实迷途其未远,觉今是而昨非。

以后,多读书,多写字,多做学问。做个独立思考的人,做个好人。

向着2019,出发!



Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×