<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ThinkChat2.0新版上線,更智能更精彩,支持會話、畫圖、視頻、閱讀、搜索等,送10W Token,即刻開啟你的AI之旅 廣告
                # 11.4 微博中的圖片 我們已經實現了微博相關的所有操作,本節要讓微博除了能輸入文字之外還能插入圖片。我們首先會開發一個基礎版本,只能在生產環境中使用,然后再做一系列功能增強,允許在生產環境上傳圖片。 添加圖片上傳功能明顯要完成兩件事:編寫用于上傳圖片的表單,準備好所需的圖片。上傳圖片按鈕和微博中顯示的圖片構思如[圖 11.18](#fig-micropost-image-mockup) 所示。[[9](#fn-9)] ![micropost image mockup](https://box.kancloud.cn/2016-05-11_57333075d7360.png)圖 11.18:圖片上傳界面的構思圖(包含一張上傳后的圖片) ## 11.4.1 基本的圖片上傳功能 我們要使用 [CarrierWave](https://github.com/carrierwaveuploader/carrierwave) 處理圖片上傳,并把圖片和微博模型關聯起來。為此,我們要在 `Gemfile` 中添加 `carrierwave` gem,如[代碼清單 11.55](#listing-gemfile-carrierwave) 所示。為了一次安裝完所有 gem,[代碼清單 11.55](#listing-gemfile-carrierwave) 中還添加了用于調整圖片尺寸的 `mini_magick`([11.4.3 節](#image-resizing))和用于在生產環境中上傳圖片的 `fog`([11.4.4 節](#image-upload-in-production))。 ##### 代碼清單 11.55:在 `Gemfile` 中添加 CarrierWave ``` source 'https://rubygems.org' gem 'rails', '4.2.2' gem 'bcrypt', '3.1.7' gem 'faker', '1.4.2' gem 'carrierwave', '0.10.0' gem 'mini_magick', '3.8.0' gem 'fog', '1.36.0' gem 'will_paginate', '3.0.7' gem 'bootstrap-will_paginate', '0.0.10' . . . ``` 然后像之前一樣,執行下面的命令安裝: ``` $ bundle install ``` CarrierWave 自帶了一個 Rails 生成器,用于生成圖片上傳程序。我們要創建一個名為 `picture` 的上傳程序: ``` $ rails generate uploader Picture ``` CarrierWave 上傳的圖片應該對應于 Active Record 模型中的一個屬性,這個屬性只需存儲圖片的文件名字符串即可。添加這個屬性后的微博模型如[圖 11.19](#fig-micropost-model-picture) 所示。[[10](#fn-10)] ![micropost model picture](https://box.kancloud.cn/2016-05-11_57333075f31c3.png)圖 11.19:添加 `picture` 屬性后的微博數據模型 為了把 `picture` 屬性添加到微博模型中,我們要生成一個遷移,然后在開發服務器中執行遷移: ``` $ rails generate migration add_picture_to_microposts picture:string $ bundle exec rake db:migrate ``` 告訴 CarrierWave 把圖片和模型關聯起來的方式是使用 `mount_uploader` 方法。這個方法的第一個參數是屬性的符號形式,第二個參數是上傳程序的類名: ``` mount_uploader :picture, PictureUploader ``` (`PictureUploader` 類在 `picture_uploader.rb` 文件中,[11.4.2 節](#image-validation)會編輯,現在使用生成的默認內容即可。)把這個上傳程序添加到微博模型,如[代碼清單 11.56](#listing-micropost-model-picture) 所示。 ##### 代碼清單 11.56:在微博模型中添加圖片上傳程序 app/models/micropost.rb ``` class Micropost < ActiveRecord::Base belongs_to :user default_scope -> { order(created_at: :desc) } mount_uploader :picture, PictureUploader validates :user_id, presence: true validates :content, presence: true, length: { maximum: 140 } end ``` 在某些系統中可能要重啟 Rails 服務器,測試組件才能通過。 如[圖 11.18](#fig-micropost-image-mockup) 所示,為了在首頁添加圖片上傳功能,我們要在發布微博的表單中添加一個 `file_field` 標簽,如[代碼清單 11.57](#listing-micropost-create-image-upload) 所示。 ##### 代碼清單 11.57:在發布微博的表單中添加圖片上傳按鈕 app/views/shared/_micropost_form.html.erb ``` <%= form_for(@micropost, html: { multipart: true }) do |f| %> <%= render 'shared/error_messages', object: f.object %> <div class="field"> <%= f.text_area :content, placeholder: "Compose new micropost..." %> </div> <%= f.submit "Post", class: "btn btn-primary" %> <span class="picture"> <%= f.file_field :picture %> </span> <% end %> ``` 注意,`form_for` 中指定了 `html: { multipart: true }` 參數。為了支持文件上傳功能,必須指定這個參數。 最后,我們要把 `picture` 添加到可通過 Web 修改的屬性列表中。為此,要修改 `micropost_params` 方法,如[代碼清單 11.58](#listing-micropost-params-picture) 所示。 ##### 代碼清單 11.58:把 `picture` 添加到允許修改的屬性列表中 app/controllers/microposts_controller.rb ``` class MicropostsController < ApplicationController before_action :logged_in_user, only: [:create, :destroy] before_action :correct_user, only: :destroy . . . private def micropost_params params.require(:micropost).permit(:content, :picture) end def correct_user @micropost = current_user.microposts.find_by(id: params[:id]) redirect_to root_url if @micropost.nil? end end ``` 圖片上傳后,在微博局部視圖中可以使用 `image_tag` 輔助方法渲染,如[代碼清單 11.59](#listing-micropost-partial-image-display) 所示。注意,我們使用了 `picture?` 布爾值方法,如果沒有圖片就不顯示 `img` 標簽。這個方法由 CarrierWave 自動創建,方法名根據保存圖片文件名的屬性而定。自己動手上傳圖片后顯示的頁面如[圖 11.20](#fig-micropost-with-image) 所示。針對圖片上傳功能的測試留作練習([11.6 節](#user-microposts-exercises))。 ##### 代碼清單 11.59:在微博中顯示圖片 app/views/microposts/_micropost.html.erb ``` <li id="micropost-<%= micropost.id %>"> <%= link_to gravatar_for(micropost.user, size: 50), micropost.user %> <span class="user"><%= link_to micropost.user.name, micropost.user %></span> <span class="content"> <%= micropost.content %> <%= image_tag micropost.picture.url if micropost.picture? %> </span> <span class="timestamp"> Posted <%= time_ago_in_words(micropost.created_at) %> ago. <% if current_user?(micropost.user) %> <%= link_to "delete", micropost, method: :delete, data: { confirm: "You sure?" } %> <% end %> </span> </li> ``` ![microposts with image](https://box.kancloud.cn/2016-05-11_57333076173f8.png)圖 11.20:發布包含圖片的微博后顯示的頁面 ## 11.4.2 驗證圖片 前一節添加的上傳程序是個好的開始,但有一定不足:沒對上傳的文件做任何限制,如果用戶上傳的文件很大,或者類型不對,會導致問題。這一節我們要修正這個不足,添加驗證,限制圖片的大小和類型。我們既會在服務器端添加驗證,也會在客戶端(即瀏覽器)添加驗證。 對圖片類型的限制在 CarrierWave 的上傳程序中設置。我們要限制能使用的圖片擴展名(PNG,GIF 和 JPEG 的兩個變種),如[代碼清單 11.60](#listing-validate-picture-format) 所示。(在生成的上傳程序中有一段注釋說明了該怎么做。) ##### 代碼清單 11.60:限制可上傳圖片的類型 app/uploaders/picture_uploader.rb ``` class PictureUploader < CarrierWave::Uploader::Base storage :file # Override the directory where uploaded files will be stored. # This is a sensible default for uploaders that are meant to be mounted: def store_dir "uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}" end # 添加一個白名單,指定允許上傳的圖片類型 def extension_white_list %w(jpg jpeg gif png) end end ``` 圖片大小的限制在微博模型中設定。和前面用過的模型驗證不同,Rails 沒有為文件大小提供現成的驗證方法。所以我們要自己定義一個驗證方法,我們把這個方法命名為 `picture_size`,如[代碼清單 11.61](#listing-micropost-model-image-validation) 所示。注意,調用自定義的驗證時使用的是 `validate` 方法,而不是 `validates`。 ##### 代碼清單 11.61:添加圖片大小驗證 app/models/micropost.rb ``` class Micropost < ActiveRecord::Base belongs_to :user default_scope -> { order(created_at: :desc) } mount_uploader :picture, PictureUploader validates :user_id, presence: true validates :content, presence: true, length: { maximum: 140 } validate :picture_size private # 驗證上傳的圖片大小 def picture_size if picture.size > 5.megabytes errors.add(:picture, "should be less than 5MB") end end end ``` 這個驗證會調用指定符號(`:picture_size`)對應的方法。在 `picture_size` 方法中,如果圖片大于 5MB(使用[旁注 8.2](chapter8.html#aside-time-helpers) 中介紹的句法),就向 `errors` 集合([6.2.2 節](chapter6.html#validating-presence)簡介過)添加一個自定義的錯誤消息。 除了這兩個驗證之外,我們還要在客戶端檢查上傳的圖片。首先,我們在 `file_field` 方法中使用 `accept` 參數限制圖片的格式: ``` <%= f.file_field :picture, accept: 'image/jpeg,image/gif,image/png' %> ``` 有效的格式使用 [MIME 類型](https://en.wikipedia.org/wiki/Internet_media_type)指定,這些類型對應于[代碼清單 11.60](#listing-validate-picture-format) 中限制的類型。 然后,我們要編寫一些 JavaScript(更確切地說是 [jQuery](http://jquery.com/) 代碼),如果用戶試圖上傳太大的圖片就彈出一個提示框(節省了上傳的時間,也減少了服務器的負載): ``` $('#micropost_picture').bind('change', function() { var size_in_megabytes = this.files[0].size/1024/1024; if (size_in_megabytes > 5) { alert('Maximum file size is 5MB. Please choose a smaller file.'); } }); ``` 本書雖然沒有介紹 jQuery,不過你或許能理解這段代碼:監視頁面中 CSS ID 為 `micropost_picture` 的元素(如 `#` 符號所示,這是微博表單的 ID,參見[代碼清單 11.57](#listing-micropost-create-image-upload)),當這個元素的內容變化時,會執行這段代碼,如果文件太大,就調用 `alert` 方法。[[11](#fn-11)] 把這兩個檢查措施添加到微博表單中,如[代碼清單 11.62](#listing-format-jquery-file-test) 所示。 ##### 代碼清單 11.62:使用 jQuery 檢查文件的大小 app/views/shared/_micropost_form.html.erb ``` <%= form_for(@micropost, html: { multipart: true }) do |f| %> <%= render 'shared/error_messages', object: f.object %> <div class="field"> <%= f.text_area :content, placeholder: "Compose new micropost..." %> </div> <%= f.submit "Post", class: "btn btn-primary" %> <span class="picture"> <%= f.file_field :picture, accept: 'image/jpeg,image/gif,image/png' %> </span> <% end %> <script type="text/javascript"> $('#micropost_picture').bind('change', function() { var size_in_megabytes = this.files[0].size/1024/1024; if (size_in_megabytes > 5) { alert('Maximum file size is 5MB. Please choose a smaller file.'); } }); </script> ``` 有一點很重要,你要知道,像[代碼清單 11.62](#listing-format-jquery-file-test) 這樣的代碼并不能阻止用戶上傳大文件。我們添加的代碼雖然能阻止用戶通過 Web 界面上傳,但用戶可以使用 Web 審查工具修改 JavaScript,或者直接發送 `POST` 請求(例如,使用 `curl`)。為了阻止用戶上傳大文件,必須在服務器端添加驗證,如[代碼清單 11.61](#listing-micropost-model-image-validation) 所示。 ## 11.4.3 調整圖片的尺寸 前一節對圖片大小的限制是個好的開始,不過用戶還是可以上傳尺寸很大的圖片,撐破網站的布局,有時會把網站搞得一團糟,如[圖 11.21](#fig-large-uploaded-image) 所示。因此,如果允許用戶從本地硬盤中上傳尺寸很大的圖片,最好在顯示圖片之前調整圖片的尺寸。[[12](#fn-12)] ![large uploaded image](https://box.kancloud.cn/2016-05-11_57333076362f4.png)圖 11.21:上傳了一張超級大的圖片 我們要使用 [ImageMagick](http://www.imagemagick.org/) 調整圖片的尺寸,所以要在開發環境中安裝這個程序。(如 [11.4.4 節](#image-upload-in-production)所示,Heroku 已經預先安裝好了。)在云端 IDE 中可以使用下面的命令安裝:[[13](#fn-13)] ``` $ sudo apt-get update $ sudo apt-get install imagemagick --fix-missing ``` 然后,我們要在 CarrierWave 中引入 [MiniMagick](https://github.com/minimagick/minimagick) 為 ImageMagick 提供的接口,還要調用一個調整尺寸的方法。[MiniMagick 的文檔](http://www.rdoc.info/github/jnicklas/carrierwave/CarrierWave/MiniMagick)中列出了多個調整尺寸的方法,我們要使用的是 `resize_to_limit: [400, 400]`,如果圖片很大,就把它調整為寬和高都不超過 400 像素,而小于這個尺寸的圖片則不調整。([CarrierWave 文檔](https://github.com/carrierwaveuploader/carrierwave#using-minimagick)中列出的方法會把小圖片放大,這不是我們需要的效果。)添加[代碼清單 11.63](#listing-image-uploader-resizing) 中的代碼后,就能完美調整大尺寸圖片了,如[圖 11.22](#fig-resized-image) 所示。 ##### 代碼清單 11.63:配置圖片上傳程序,調整圖片的尺寸 app/uploaders/picture_uploader.rb ``` class PictureUploader < CarrierWave::Uploader::Base include CarrierWave::MiniMagick process resize_to_limit: [400, 400] storage :file # Override the directory where uploaded files will be stored. # This is a sensible default for uploaders that are meant to be mounted: def store_dir "uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}" end # 添加一個白名單,指定允許上傳的圖片類型 def extension_white_list %w(jpg jpeg gif png) end end ``` ![resized image](https://box.kancloud.cn/2016-05-11_5733307663470.png)圖 11.22:調整尺寸后的圖片 ## 11.4.4 在生產環境中上傳圖片 前面使用的圖片上傳程序在開發環境中用起來不錯,但圖片都存儲在本地文件系統中(如[代碼清單 11.63](#listing-image-uploader-resizing) 中 `storage :file` 那行所示),在生產環境這么做可不好。[[14](#fn-14)]所以,我們要使用云存儲服務存儲圖片,和應用所在的文件系統分開。[[15](#fn-15)] 我們要使用 `fog` gem 配置應用,在生產環境使用云存儲,如[代碼清單 11.64](#listing-image-uploader-production) 所示。 ##### 代碼清單 11.64:配置生產環境使用的圖片上傳程序 app/uploaders/picture_uploader.rb ``` class PictureUploader < CarrierWave::Uploader::Base include CarrierWave::MiniMagick process resize_to_limit: [400, 400] if Rails.env.production? storage :fog else storage :file end # Override the directory where uploaded files will be stored. # This is a sensible default for uploaders that are meant to be mounted: def store_dir "uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}" end # 添加一個白名單,指定允許上傳的圖片類型 def extension_white_list %w(jpg jpeg gif png) end end ``` 在[代碼清單 11.64](#listing-image-uploader-production) 中,使用[旁注 7.1](chapter7.html#aside-rails-environments) 中介紹的 `production?` 布爾值方法根據所在的環境選擇存儲方式: ``` if Rails.env.production? storage :fog else storage :file end ``` 云存儲服務有很多,我們要使用其中一個最受歡迎并且支持比較好的——Amazon 的 [Simple Storage Service](http://aws.amazon.com/s3/)(簡稱 S3)。[[16](#fn-16)]基本步驟如下: 1. 注冊一個 [Amazon Web Services](http://aws.amazon.com/) 賬戶; 2. 通過 [AWS Identity and Access Management](http://aws.amazon.com/iam/)(簡稱 IAM) 創建一個用戶,記下訪問公鑰和密鑰; 3. 使用 [AWS Console](https://console.aws.amazon.com/s3) 創建一個 S3 bucket(名字自己定),然后賦予上一步創建的用戶讀寫權限。 關于這些步驟的詳細說明,參見 [S3 的文檔](http://aws.amazon.com/documentation/s3/)。(如果需要還可以搜索。) 創建并配置好 S3 賬戶后,創建 CarrierWave 配置文件,寫入[代碼清單 11.65](#listing-carrier-wave-configuration) 中的內容。注意:如果做了這些設置之后連不上 S3,可能是區域位置的問題。有些用戶要在 fog 的配置中添加 `:region =&gt; ENV['S3_REGION']`,然后在命令行中執行 `heroku config:set S3_REGION=&lt;bucket_region&gt;`,其中 `bucket_region` 是你所在的區域,例如 `'eu-central-1'`。如果想找到你所在的區域,請查看 [Amazon AWS 的文檔](http://docs.aws.amazon.com/general/latest/gr/rande.html)。 ##### 代碼清單 11.65:配置 CarrierWave 使用 S3 config/initializers/carrier_wave.rb ``` if Rails.env.production? CarrierWave.configure do |config| config.fog_credentials = { # Amazon S3 的配置 :provider => 'AWS', :aws_access_key_id => ENV['S3_ACCESS_KEY'], :aws_secret_access_key => ENV['S3_SECRET_KEY'] } config.fog_directory = ENV['S3_BUCKET'] end end ``` 和生產環境的電子郵件配置一樣([代碼清單 10.56](chapter10.html#listing-sendgrid-config)),[代碼清單 11.65](#listing-carrier-wave-configuration) 也使用 Heroku 中的 `ENV` 變量,沒直接在代碼中寫入敏感信息。在 [10.3 節](chapter10.html#email-in-production),電子郵件所需的變量由 SendGrid 擴展自動定義,但現在我們要自己定義,方法是使用 `heroku config:set` 命令,如下所示: ``` $ heroku config:set S3_ACCESS_KEY=<access key> $ heroku config:set S3_SECRET_KEY=<secret key> $ heroku config:set S3_BUCKET=<bucket name> ``` 配置好之后,我們可以提交并部署了。我們先提交主題分支中的變動,然后再合并到 `master` 分支: ``` $ bundle exec rake test $ git add -A $ git commit -m "Add user microposts" $ git checkout master $ git merge user-microposts $ git push ``` 然后部署,重設數據庫,再重新把示例數據載入數據庫: ``` $ git push heroku $ heroku pg:reset DATABASE $ heroku run rake db:migrate $ heroku run rake db:seed ``` Heroku 已經安裝了 ImageMagick,所在生產環境中調整圖片尺寸和上傳功能都能正常使用,如[圖 11.23](#fig-image-upload-production) 所示。 ![image upload production](https://box.kancloud.cn/2016-05-11_5733307688656.png)圖 11.23:在生產環境中上傳圖片
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看