- ubuntu12.04环境下使用kvm ioctl接口实现最简单的虚拟机
- Ubuntu 通过无线网络安装Ubuntu Server启动系统后连接无线网络的方法
- 在Ubuntu上搭建网桥的方法
- ubuntu 虚拟机上网方式及相关配置详解
CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.
这篇CFSDN的博客文章如何使用 Rails 和七牛云存储,在 15 分钟内打造一个图片分享社交应用原型由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.
十年前,Web 应用框架 Rails 创始人 David Heinemeier Hansson 曾录制视频,向我们演示如何使用 Ruby on Rails 在 15 分钟内创作一个 blog 引擎。这个视频通过 Rails 优秀的 MVC 、习惯优于配置(Convention over Configuration)等设计,以及强大的代码生成、scaffold 等功能,成功展示了 Ruby on Rails 编写 Web 应用核心功能的高效简洁。Ruby on Rails 这门技术也在 Web 2.0 时代大放异彩,成为了 Web 应用开发最佳的技术方案选择之一.
经过十年的发展,软件行业早已迈入云计算时代。为了应对大规模的访问量,同时控制研发和运营成本,作为云计算基石的云存储,已经成为了 Web 开发必不可少的基础设施。今天,就让我们一起来看看如何使用 Rails 和七牛云存储,在 15 分钟内打造一个图片分享社交应用原型.
七牛云存储 是一个公有云服务,提供海量对象存储功能,以及云端文件处理和分发服务。开始之前,我们需要创建一个七牛云存储 试用帐户,并且了解一些基础知识:
七牛云存储是一个 Key-Value 形式的对象存储系统,一个 key 对应一个资源(文件)。 资源必须存储在某个空间(Bucket)中,不可单独存在。一个帐户可以创建多个空间.
创建基本 Rails 项目 。
你应该可以使用 Ruby 1.9 以上,Rails 3.0 以上的任意版本,本例中我们使用的是 Ruby 2.2.3 和 Rails 4.2.5.
安装好 Ruby 和 Rails 之后,使用 rails 命令创建应用程序 konata 的目录结构和基本文件:
。
稍候这条命令执行完成,我们立即得到了一个可以运行的空白 Rails 应用程序,执行以下命令,并在浏览器中访问 http://localhost:3000 查看运行效果:
。
。
。
使用 Rails Scaffold 实现 CRUD 。
我们将使用 Rails 的 scaffold 功能,生成用于处理图片发表的 model、controller、view,以及 database migration 等源代码文件.
。
访问 http://localhost:3000/posts 可以看到,我们已经获得了 post 的完整 CRUD 功能,只是暂时还不能上传图片.
。
使用七牛 API 实现图片上传 。
修改 Gemfile,在其中加入对七牛 Ruby SDK 的引用:
。
。
执行以下命令安装七牛 Ruby SDK。这里原本应该执行 bundle 进行安装,但由于七牛 Ruby SDK 依赖的 mime-types 版本设定比较保守,需要使用 bundle update 命令降级 mime-types,解决依赖冲突.
。
。
编辑 config/secrets.yml,在其中加入七牛云存储帐户的密钥:
。
。
创建 config/initializers/qiniu.rb,使用刚才加入的密钥与七牛云存储服务器建立连接。内容如下:
1
2
3
4
5
6
|
require
'qiniu'
Qiniu.establish_connection!(
access_key: Rails.application.secrets.qiniu_access_key,
secret_key: Rails.application.secrets.qiniu_secret_key
)
|
注意:
AccessKey 和 SecretKey 必须绝对保密,不可出现在用户可以查看的 Web 前端源代码里,或是编译进客户端二进制代码中.
七牛 API 提供了多种上传方式 以满足不同的业务场景需求。这里我们选择使用最有代表性,也最简单的 HTML 表单上传+HTTP 303 重定向返回的方式实现客户端文件直接上传七牛云存储。这种方法的好处是客户端文件无需通过业务服务器(app server)中转,既可以利用七牛强大的 CDN 优化上传速度及提高可靠性,也可以节省业务服务器带宽.
编辑 app/views/posts/_form.html.erb,根据七牛云存储 SDK 构造上传表单。注意其中的上传凭证字段,我们将在 PostsController 里创建它:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
<%= form_tag
'http://upload.qiniu.com'
, multipart:
true
do
%>
<%= hidden_field_tag
:token
,
@qiniu_upload_token
%>
<div
class
=
"field"
>
<%= label_tag
:title
%><br>
<%= text_field_tag
'x:title'
%>
</div>
<div
class
=
"field"
>
<%= label_tag
:image
%><br>
<%= file_field_tag
:file
%>
</div>
<div
class
=
"actions"
>
<%= submit_tag
'Create'
%>
</div>
<%
end
%>
|
编辑 app/controllers/posts_controller.rb,添加代码生成上传凭证,以及根据七牛云存储自定义响应内容创建 post 实例:
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
|
def
new
@qiniu_upload_token
= generate_qiniu_upload_token
@post
= Post.
new
end
def
create
upload_ret =
JSON
.parse(Base64.urlsafe_decode64(params[
:upload_ret
]))
@post
= Post.
new
(
title: upload_ret[
'title'
],
filename: upload_ret[
'fname'
],
qiniu_hash: upload_ret[
'hash'
]
)
# ...
end
private
def
generate_qiniu_upload_token
put_policy = Qiniu::Auth::PutPolicy.
new
(
'konata'
)
put_policy.return_body = {
fname:
'$(fname)'
,
hash:
'$(etag)'
,
title:
'$(x:title)'
}.to_json
put_policy.return_url = create_posts_url
Qiniu::Auth.generate_uptoken(put_policy)
end
|
编辑 config/routes.rb,将 create action 定义为使用 get 方法亦可访问
1
2
3
4
5
|
resources
:posts
do
collection
do
get
'create'
, as:
:create
end
end
|
重新启动 rails server,访问 http://localhost:3000/posts/new,现在我们已经可以在发表新 post 的时候上传图片至七牛云存储.
提示:
文件将会上传到名为 konata 的公开空间(bucket)。 我们没有在代码中指定 key,七牛云存储默认会使用根据文件内容计算的 hash (etag) 值做为 key。这种做法可以非常简单地避免内容相同的文件存储多份浪费空间。 由于上传表单将会直接提交到七牛云存储服务器,我们的应用程序后端无法获得 title 等业务对象字段,我们使用七牛云存储 API 的 自定义变量 和 自定义响应内容 功能,通过七牛云存储上传 API 中转获得这些字段。 展示用户上传的图片 。
修改 app/helpers/application_helper.rb,添加 qiniu_image_url 方便生成图片 URL。为了保持简单我们直接硬编码了空间的域名:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
def
qiniu_image_url(post, format =
:raw
)
url =
"http://7xokus.com2.z0.glb.qiniucdn.com/#{post.qiniu_hash}"
case
format
when
:square
url <<
'?imageView2/1/w/300/h/300/q/90'
when
:preview
url <<
'?imageView2/2/w/1000/h/1000/q/90'
when
:raw
url <<
"?attname=#{post.filename}"
else
url
end
end
|
修改 app/views/posts/index.html.erb 和 app/views/posts/show.html.erb,调用刚才创建的 URL helper 展示图片:
1
2
3
4
5
|
<tr>
<td><%= post.title %></td>
<td><%= link_to image_tag(qiniu_image_url(post,
:square
), size:
'300'
), post %></td>
<td><%= link_to
'Destroy'
, post, method:
:delete
, data: { confirm:
'Are you sure?'
} %></td>
</tr>
|
1
2
3
4
5
|
<p>
<%= link_to image_tag(qiniu_image_url(
@post
,
:preview
)), qiniu_image_url(
@post
),
class
:
'image'
%>
</p>
<%= link_to
'Back'
, posts_path %>
|
修改 config/routes.rb,将网站根目录设置为 posts 列表页面:
root 'posts#index' 访问 http://localhost:3000,现在我们可以看到刚才上传的图片.
提示:
每个空间(bucket)内的资源都可以通过该空间的默认或自定义域名,加上文件 key 构造的 HTTP URL 进行访问。 可以在 URL 后增加特定查询参数,调用七牛云存储强大的 数据处理(Fop) API,实时生成自定义格式的缩略图。 可以通过查询参数 attname 指定 URL 下载时使用的文件名。 简单的 UI 美化 。
修改 app/views/posts/index.html.erb,将原有的 table 布局改为 flexbox 布局:
1
2
3
4
5
6
7
8
9
10
11
|
<div
class
=
"posts"
>
<%
@posts
.
each
do
|post| %>
<p>
<%= link_to image_tag(qiniu_image_url(post,
:square
), size:
'300'
), post,
class
:
'image'
%>
<br>
<%= post.title %>
<br>
<%= link_to
'Destroy'
, post, method:
:delete
, data: { confirm:
'Are you sure?'
} %>
</p>
<%
end
%>
</div>
|
修改 app/assets/stylesheets/application.css,加入对应的 CSS:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
body {
padding: 20px;
}
a.image
:hover
{
background-color: transparent;
}
div.posts {
display: flex;
flex-flow: row wrap;
justify-content: space-between;
}
|
访问 http://localhost:3000,图片列表看起来像一个正常的相册了.
添加用户账户功能 。
我们的应用程序还有两个明显的问题:没有记录图片是由谁分享的;任何人都可以删除 post。这对于一个社交应用来说显然是不能接受的问题。这对于一个社交应用来说显然是不可接受的,所以接下来我们将使用 Rails 社区流行的 Devise 组件直接获得用户注册、登录、验证子系统,实现图片发表者信息记录等功能.
修改 Gemfile,加入对 Devise 的依赖:
。
。
执行以下命令安装 Devise,生成 User model,以及我们所需的 data migration:
。
。
修改 app/controllers/posts_controller.rb,对查看以外的操作要求登录,并在发表 post 时记录发表者身份:
1
2
3
4
5
6
7
8
9
10
11
12
|
before_action
:authenticate_user
!, except: [
:index
,
:show
]
def
create
# ...
@post
= Post.
new
(
title: upload_ret[
'title'
],
filename: upload_ret[
'fname'
],
qiniu_hash: upload_ret[
'hash'
],
creator: current_user
)
# ...
end
|
修改 app/models/post.rb,添加与 User model 的从属关联:
。
修改 app/views/layouts/application.html.erb,添加登录状态信息和注销链接:
。
1
2
3
4
5
6
7
8
|
<header>
<%
if
user_signed_in? %>
<p>
Hello <%= current_user.email %>
<%= link_to
'Logout'
, destroy_user_session_path, method:
:delete
%>
</p>
<%
end
%>
</header>
|
修改 app/views/posts/index.html.erb,限制仅 post 发表者可以删除该 post:
1
2
3
4
|
<%
if
user_signed_in?
and
post.creator == current_user %>
<br>
<%= link_to
'Destroy'
, post, method:
:delete
, data: { confirm:
'Are you sure?'
} %>
<%
end
%>
|
重启 rails server 后,访问 http://localhost:3000,现在用户需要注册登录才能发表图片了.
实现点赞功能 。
最后,做为一个社交应用,没有点赞功能怎么能让点赞狂魔们满足呢?!我们将添加一个 like scaffold 用来处理点赞和存储点赞信息.
执行以下命令生成 scaffold,Like model 将做为一个 join model 同时从属于 Post 和 User:
。
。
修改 app/models/post.rb,建立 Post 与 Like model 的“拥有/嵌套”关系:
。
修改 app/models/like.rb,限制一个点赞狂魔对一个 post 只能点一次赞:
。
。
修改 config/routes.rb,将 likes 设置为 posts 的嵌套资源:
。
。
修改 app/views/posts/index.html.erb,添加点赞信息显示以及 AJAX 点赞链接:
。
1
2
3
4
5
6
7
8
9
10
11
12
|
<%= post.title %>
<br>
<%= content_tag(
:span
,
"#{post.likes.count} likes"
, id:
"post_#{post.id}_likes"
) %>
<%
if
user_signed_in? %>
<br>
<%= link_to
'Like'
, post_likes_path(post), method:
:post
, remote:
true
%>
<%
if
post.creator == current_user %>
<%= link_to
'Destroy'
, post, method:
:delete
, data: { confirm:
'Are you sure?'
} %>
<%
end
%>
<%
end
%>
|
修改 app/controllers/likes_controller.rb,真正将 likes 资源实现为 posts 的嵌套资源,并在点赞时记录点赞狂魔的身份:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
before_action
:set_post
def
create
@like
=
@post
.likes.
new
(user: current_user)
respond_to
do
|format|
if
@like
.save
format.js { }
else
format.js { }
end
end
end
private
def
set_post
@post
= Post.find(params[
:post_id
])
end
|
创建 app/views/likes/create.js.erb,使用 Server-generated JavaScript 更新点赞信息:
。
重启 rails server 后,访问 http://localhost:3000,让我们愉快地点赞吧~ 。
。
小结 。
虽然这只是一个简单的原型,但是因为使用了七牛云存储作为图片存储后端,我们的社交应用产品在一开始的原型阶段就拥有了能为大规模用户提供高速、可靠服务的潜能.
简单回顾一下我们刚才学习到的内容吧。使用 Rails 的代码生成功能, 基于 CRUD 结构的 scaffold 实现业务对象维护,以及业务操作非常高效;使用七牛云存储则可以轻松处理业务系统中的文件存储,获得图片视频等多媒体文件的云端处理能力,减少,甚至避免了部分研发和运维工作。希望这个视频可以帮助大家认识这两个优秀的开发工具,直观感受到它们的高效强大和简单易用.
参考资料 。
Ruby on Rails Guides 七牛开发者中心 。
示例代码 。
https://github.com/rainux/konata-sample 。
比起直接试用示例代码,你应该按照教程自己编写这些代码,亲自编写代码有助于加深理解和记忆.
最后此篇关于如何使用 Rails 和七牛云存储,在 15 分钟内打造一个图片分享社交应用原型的文章就讲到这里了,如果你想了解更多关于如何使用 Rails 和七牛云存储,在 15 分钟内打造一个图片分享社交应用原型的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
sanitize 是什么意思在 Rails 中是什么意思? 我正在阅读 CanCanCan 的文档.它说: When using strong_parameters or Rails 4+, you
在过去的几个月里,我感觉自己对 Ruby on Rails (RoR) 开发的了解达到了极限。我为大/小客户和 friend /爱好项目开发了大大小小的应用程序。我知道如何开发这些应用程序,但开始感觉
我昨天参加了一个关于扩展 Rails 的聚会,其中一个主题是 Hexagonal Rails。然而,我只做了一年的 Rails,对 MVC 结构非常满意(也许太舒服了),所以我不太了解适配器和消息队列
我使用多个 Rails 应用程序,一些在 Rails 3.2/Ruby 2.0 上,一些在 Rails 2.3/Ruby 1.8.7 上。 他们的共同点是,随着他们的成长和添加更多的依赖项/ gem
这个问题在这里已经有了答案: Using Rails-UJS in JS modules (Rails 6 with webpacker) (5 个答案) 关闭 3 年前。 我正在尝试使用 UJS
我正在开发一个当前使用 Rails 1.2 的 Rails 应用程序,所以我现在离最新的稳定版本(Rails 2.3)还有很长的路要走。 我应该如何进行迁移到更新版本的 Rails 的过程? 我应该一
尝试按照 Ryan Bates Backbone.js 教程构建抽奖应用程序,但我已经遇到了第一段代码的问题。在 application.js 的 init 函数中,他初始化了 Raffler 路由的
我正在使用 Rails 3.2 并且我有一个数据库表,我想在其中找到符合以下条件的所有行: a = true and b = true and ( 0 true, :b =>
我有一个用户类和一个联系人,其中联系人是用户的子类。这两个类都存储在用户表中。 我的联系人可能有也可能没有电子邮件地址,而我的用户需要一个电子邮件地址(我的用户模型定义中有 validates_pre
我正在编写一个教程,我在其中演示了一些 rails 命令。在我的机器上 rails和 script/rails两者都同样有效。有“首选”形式吗?两者中哪一个更普遍? 最佳答案 当您运行 rails 时
我正在寻找有关通过我的应用程序前进的最佳方式的建议,这是我首次开始集成Elasticsearch。我是一名初学者,但是热衷于深入研究,以便原谅任何明显的错误! 我遵循了http://www.sitep
我刚刚用 Rails new 启动了一个新的 Rails 应用程序,将默认数据库设置更改为 PostgresSQL。我用 bin/rails s 启动服务器,结果很奇怪 2016-04-21 05:0
我收到一个参数并希望它是这样的字符串: "abc,efg" 或者像这样的数组 ["abc","efg"] 在第一种情况下,我想将它转换成一个数组,什么是好的方法? 这是我的想法 if params[:
我刚刚用 Rails new 启动了一个新的 Rails 应用程序,将默认数据库设置更改为 PostgresSQL。我用 bin/rails s 启动服务器,结果很奇怪 2016-04-21 05:0
我收到一个参数并希望它是这样的字符串: "abc,efg" 或者像这样的数组 ["abc","efg"] 在第一种情况下,我想将它转换成一个数组,什么是好的方法? 这是我的想法 if params[:
我有 Rails 4,这是我的默认版本(我仍然希望它是)。但我不想在我的电脑上添加 rails 3.2。在以下命令中:gem install rails -v 3.2.16 我有这个警告: railt
您好,我想使用 Sheevaplug 构建一个“Rails Brick”来自 Marvell(操作系统是开箱即用的 Ubuntu,但您可以在其上安装其他发行版)。它将成为家庭服务器和静音、低成本(99
我需要能够从 Rails 控制台发送我的 Rails 应用程序的 Postgres 数据库中所有未接受的邀请。 (我有一个名为 Invitations 的表,其中包含一个名为 accepted 的 b
validate :cannot_modify_if_locked, on: :update def cannot_modify_if_locked if self.locked erro
我正在学习教程(学习 Rails 播客),需要更改以下路由语法,以便它与 Rails 3.0 兼容。谁能帮忙? map.view_page ':name', :controller => 'viewe
我是一名优秀的程序员,十分优秀!