almost 2 years ago

## 北醫:

### 抓A醫生的個人頁面

- 要用to_html，把Nokogiri::XML::NodeSet轉成html，不然沒辦法用scan
- 參考Nokogiri 問題求救
- Regex

wget記得要用包起來。
-P 是指定資料夾 ( --directory-prefix=)
-O 是改變檔案名稱 (--output-document=)

Paperclip Gem：一般來講，用Paperclip上傳檔案，會存三種大小的檔案在Project_name/public/system/裡面，

a. JC.rb檔案做在project_name/lib
b. 剛做好的時候，可以用ruby JC.rb
c. 然後到config/application.rbrequirerequire "JC" (不要有.rb)
d. require之後，可以用rails c試看看，先require "JC"，然後再JC.run (我是設定self.run)
e. 還可以到view去使用 <%= JC.run %>，不過server記得要重開

almost 2 years ago

## 如何使用Git

1.開始使用:

branches config description HEAD hooks info objects refs等資料夾

2.把遠端的東西抓下來

3.檢查狀態

4.開始測試：弄一個project2

5.全部加到一個暫存的狀態

6.換到project 2git pull下來
7.衝突的解法

8.解法：git pull

9.git add filename之後會變成modified，這樣就可以commit了

10.到projct 2，再執行git pull，就可以了
11.git pull之後，如果沒有conflict，就會auto merge成功，就會進到commit的畫面
12.講branch：新增brance

13.小寫d刪除，還沒被merge

1. 大寫D，強制刪除 15.換到新的branchname 16.兩個branches要merge時正確的做法 merge要先由branch去合併master 然後再由master去合併branch 17.git log 可以看過去的所有的commit git checkout commit_number

18.34:00 git總整理

## ROR TUTORIAL (3RD ED.) Ch12 Following users

1. 記得弄個新branch
2. map怎麼寫

1. hobbes.followers: 有哪些追隨者
2. calvin.following: 追隨了哪些人
3. 用Relationship model 來當中介可以簡化結構 $rails generate model Relationship follower_id:integer followed_id:integer 4. 為了效率，所以增添index Because we will be finding relationships by follower_id and by followed_id, we should add an index on each column for efficiency, as shown in Listing 12.1. 5. add_index :relationships, [:follower_id, :followed_id], unique: true這行可以避免user重覆跟隨另一個user Listing 12.1 also includes a multiple-key index that enforces uniqueness on (follower_id, followed_id) pairs, so that a user can’t follow another user more than once. (Compare to the email uniqueness index from Listing 6.28 and the multiple-key index in Listing 11.1.) As we’ll see starting in Section 12.1.4, our user interface won’t allow this to happen, but adding a unique index arranges to raise an error if a user tries to create duplicate relationships anyway (for example, by using a command-line tool such as curl). 6. 因為都是User，所以另外取名會比較好記。取名作follower跟followes，但其實都是連結回去User Class 這邊是跟隨者has_many :active_relationships, class_name: "Relationship",foreign_key: "follower_id",dependent: :destroy 這邊是跟隨誰：has_many :following, through: :active_relationships, source: :followed Rails would see “followeds” and use the singular “followed”, assembling a collection using the followed_id in the relationships table. But, as noted in Section 12.1.1, user.followeds is rather awkward, so we’ll write user.following instead. Naturally, Rails allows us to override the default, in this case using the source parameter (as shown in Listing 12.8), which explicitly tells Rails that the source of the following array is the set of followed ids. 跟隨者：是active的關係 跟隨誰：是passive的關係 其實都是連到Relationship這個table，這樣取名(:active_relationships:passive_relationships)是為了比較好了解。要用class_name 然後要去找到特定的foreign_key，active去找follower_id，passive去找followed_id 7. 跟隨誰，應該是用followed，不過英文語法不對，所以改成following，不過還是要讓rails知道要去哪裡找，所以要加上source: :followed Rails would see “followeds” and use the singular “followed”, assembling a collection using the followed_id in the relationships table. But, as noted in Section 12.1.1, user.followeds is rather awkward, so we’ll write user.following instead. Naturally, Rails allows us to override the default, in this case using the source parameter (as shown in Listing 12.8), which explicitly tells Rails that the source of the following array is the set of followed ids. 8. 跟隨跟不跟隨 Follows a user. Unfollows a user. Returns true if the current user is following the other user. 9. user.following => 會利用follower_id這個foreign key，去找active_relationships的followed_id (用source告知) (會利用follower_id：跟隨者有幾個被跟隨者) Figure 12.7: A model of followed users through active relationships. user.followers => 會利用followed_id這個foreign key，去找passive_relationships的follower_id (用source告知) (會利用followed_id：被跟隨的這個人有幾個跟隨者) Figure 12.9: A model for user followers through passive relationships. 其實follower_id跟followed_id都是跑回去User放在relationship裡面的foreign_key 10. 12.2.1 Sample following data 可以先用db/seeds.rb來互相跟隨 11. 12.2.2 Stats and a follow form /users/1/following/users/1/followers You might suspect that the URLs for following and followers will look like /users/1/following and /users/1/followers, and that is exactly what the code in Listing 12.15 arranges. Since both pages will be showing data, the proper HTTP verb is a GET request, so we use the get method to arrange for the URLs to respond appropriately. Meanwhile, the member method arranges for the routes to respond to URLs containing the user id. The other possibility, collection, works without the id, so that /users/tigers would respond to the URL /users/tigers (presumably to display all the tigers in our application). 12. 用partial來做view 13. count可以在資料庫裡面直接計算數字出來，比較有效率 As in that case, Rails calculates the count directly in the database for efficiency. 14. partial的使用方法：<%= render 'shared/stats' %> 15. _follow_form.html.erb這個partial，用render執行另外兩個partial：_follow.html.erb_unfollow.html.erb 跟隨的partial，要記得hidden_field_tag:followed_idcreate action 這邊是用build 其實只是個button(還不能作用，因為還沒有寫好controller，要到12.2.4才行) 解除跟隨的partial，這邊是delete，其實只是個button(還不能作用，因為還沒有寫好controller，要到12.2.4才行) 16. Listing12.16的stats parital裡面的<%= following_user_path(@user) %><%= followers_user_path(@user) %>必須要靠Listing12.15裡面的member去寫出來，可是Controller跟View都還沒寫好，就要看Listing 12.25跟Listing 12.26 註：member寫好會變這樣，網址會是：/users/1/following/users/1/followers但要記得回去Controller寫Action/Method = followingfollowers HTTP request URL Action Named route GET /users/1/following following following_user_path(1) GET /users/1/followers followers followers_user_path(1) 17. 12.2.4：開始讓button可以用 $ rails generate controller Relationships
幫用戶A在用戶Ｂ的頁面，看下follow button(12.21)之後，會將:followed_id送到Relationships Controllercreate method去 (12.32)，執行user = User.find(params[:followed_id])，接著執行current_user.follow(user)，會跑回去12.10的follow methodactive_relationships.create(followed_id: other_user.id)，在Relationships Model的table裡面新增一列

18. 開始用ajax，只要在view的地方加remote: true，然後在controller也要加東西
就好 12.2.5 A working follow button with Ajax

這樣的寫法，即使是JavaScript 被停用了還是可以使用，不過還是要加點東西

而且還要去把這兩個檔案寫好：create.js.erbdestroy.js.erb

19. map怎麼用？
Micropost.where("user_id = ?", id)
Micropost.where("user_id IN (?) OR user_id = ?", following_ids, id)
[1, 2, 3, 4].map { |i| i.to_s }
[1, 2, 3, 4].map(&:to_s)
User.first.following.map(&:id)
User.first.following_ids
User.first.following_ids.join(', ')
Micropost.where("user_id IN (?) OR user_id = ?", following_ids, id)
有5000 users就爆了

20. subselect 子查詢
Micropost.where("user_id IN (?) OR user_id = ?", following_ids, id)
Micropost.where("user_id IN (:following_ids) OR user_id = :user_id", following_ids: following_ids, user_id: id)
following_ids = "SELECT followed_id FROM relationships WHERE follower_id = :user_id"
大概是這個樣子：
SELECT * FROM microposts WHERE user_id IN (SELECT followed_id FROM relationships WHERE follower_id = 1) OR user_id = 1

## ROR TUTORIAL (3RD ED.) Ch11 User microposts

1. 每次都要新增一個branch
2. 怎麼使用Amazon.com’s Simple Storage Service (S3)
3. user:references這樣寫可以直接產生關聯，然後會有user_id (belongs_to :user會自動產生)

The generate command produces a migration to create a microposts table in the database (Listing 11.1); compare it to the analogous migration for the users table from Listing 6.2. The biggest difference is the use of references, which automatically adds a user_id column (along with an index and a foreign key reference)3 for use in the user/micropost association.

4. 把micropost叫出來的時候，要按特定的user，還要有特定的順序，所以:user_id:create_at都要記得上index
Because we expect to retrieve all the microposts associated with a given user id in reverse order of creation, Listing 11.1 adds an index (Box 6.2) on the user_id and created_at columns:

By including both the user_id and created_at columns as an array, we arrange for Rails to create a multiple key index, which means that Active Record uses both keys at the same time.

5. 要記得rake db:migrate，資料庫才會被更新。
With the migration in Listing 11.1, we can update the database as usual:

6. assert @micropost.valid?答案是valid，所以assert會是true (因為都還沒有設任何的validation，要到micropost.rb去設validates :user_id, presence: true)

7. 'assert_not @micropost.valid?' 答案是valid，所以assert_not會是false (因為都還沒有設任何的validation，要到micropost.rb去設validates :user_id, presence: true)

8. assert_not @micropost.valid?也會是valid，雖然@micropost.content是空白的，但因為沒有validation，所以還是valid。

9. assert_not @micropost.valid?也是valid，因為還沒有設定少於140個字母。

10. 要這樣設才有會讓7跟8是not valid，然後才會變true：validates :content, presence: true, length: { maximum: 140 }

11. 第二個寫法才是正確的，可以順便產生user_id

These latter methods constitute the idiomatically correct way to make a micropost, namely, through its association with a user. When a new micropost is made in this way, its user_id is automatically set to the right value.

12. 這邊又要去想一下newbuild的差別
(As with new, build returns an object in memory but doesn’t modify the database.)

13. default_scope可以將資料從資料庫按照我們所需要的順序叫出來
We’ll get the test to pass using a Rails method called default_scope, which among other things can be used to set the default order in which elements are retrieved from the database

14. 'order'是default_scope的一個argument
To enforce a particular order, we’ll include the order argument in default_scope, which lets us order by the created_at column as follows:order(:created_at)

15. 這樣就可以由新到舊的。
default_scope -> { order(created_at: :desc) }
Listing 11.16 introduces the “stabby lambda” syntax for an object called a Proc (procedure) or lambda, which is an anonymous function (a function created without a name). The stabby lambda -> takes in a block (Section 4.3.2) and returns a Proc, which can then be evaluated with the call method. We can see how it works at the console:
Proc(procedure)跟lambda是匿名函數(不需要取名字)，然後可以用call 去呼叫。

16. dependent: :destroy: user被刪除的時候，user的micropost也要被刪除，所以是要放在user.rb
has_many :microposts, dependent: :destroy

17. render @users這樣的寫法，rails會自己去找_user.html.erb的partial。所以我們可以用render @microposts去找 _micropost.html.erb 的partial

automatically renders each of the users in the @users variable using the _user.html.erb partial. We’ll define an analogous _micropost.html.erb partial so that we can use the same technique on a collection of microposts as follows:

18. <%= will_paginate @microposts %>will_paginate如果是放在User Controller，會自動去找@user這個變數，如果是放在User Controller，但是又希望他去找其他的變數，如@microposts，那就要把變數寫在後面。如<%= will_paginate @microposts %>。要記得定義@microposts，@microposts = @user.microposts.paginate(page: params[:page])
As before, we’ll use the will_paginate method:<%= will_paginate @microposts %>
If you compare this with the analogous line on the user index page, Listing 9.41, you’ll see that before we had just<%= will_paginate %>
This worked because, in the context of the Users controller, will_paginate assumes the existence of an instance variable called @users (which, as we saw in Section 9.3.3, should be of class ActiveRecord::Relation). In the present case, since we are still in the Users controller but want to paginate microposts instead, we’ll pass an explicit @microposts variable to will_paginate. Of course, this means that we will have to define such a variable in the user show action (Listing 11.22).

19. count的好處：不會把所有資料從資料庫叫出來，然後再去計算長度，這樣太沒效率。'count'會直接在資料庫裡面先算好數量之後。
更進階的可以使用counter cache
As with paginate, we can use the count method through the association. In particular, count does not pull all the microposts out of the database and then call length on the resulting array, as this would become inefficient as the number of microposts grew. Instead, it performs the calculation directly in the database, asking the database to count the microposts with the given user_id (an operation for which all databases are highly optimized). (In the unlikely event that finding the count is still a bottleneck in your application, you can make it even faster using a counter cache.)

20. resources :microposts, only: [:create, :destroy] : 不需要new跟dit，只要create跟destroy因為大部份的動作都要在Profile跟Home執行。
the interface to the Microposts resource will run principally through the Profile and Home pages, so we won’t need actions like new or edit in the Microposts controller; we’ll need only create and destroy.

21. logged_in_user這個filter本來是放在User Controller裡面，可是因為現在Microposts Controller也要用，所以把他拿到Application controller裡面去，所有的Controller都可以用了!
Writing the application code needed to get the tests in Listing 11.30 to pass requires a little refactoring first. Recall from Section 9.2.1 that we enforced the login requirement using a before filter that called the logged_in_user method (Listing 9.12). At the time, we needed that method only in the Users controller, but now we find that we need it in the Microposts controller as well, so we’ll move it into the Application controller, which is the base class of all controllers (Section 4.4.4). The result appears in Listing 11.31.

22. 如果登入，就顯示app/views/shared/_user_info.html.erbapp/views/shared/_micropost_form.html.erb

23. _micropost_form.html.erb這個partial是在home.html.erb裡面，所以裡面的@micropost要在static_pages_controller.rb裡面定義，不過這個變數@micropost還是會送到Micropost Controller的create method去，所以Create那邊要接好micropoat_params

24. 每個user都要有feed，所以會把feed method放在User Controller裡。Micropost.where("user_id = ?", id)
我的理解：在User的Profile裡，如果要叫出來一個User所有的microposts的話，因為有關聯的關係，所以可以打成@user.microposts，不過為了增加易讀性，所以要把它包裝在feed method裡面，就可以改寫成@user.feed。
Since each user should have a feed, we are led naturally to a feed method in the User model, which will initially just select all the microposts belonging to the current user. We’ll accomplish this using the where method on the Micropost model (seen briefly before in Section 10.5), as shown in Listing 11.44.10

Alert readers might note at this point that the code in Listing 11.44 is essentially equivalent to writing

We’ve used the code in Listing 11.44 instead because it generalizes much more naturally to the full status feed needed in Chapter 12.

25. ("user_id = ?", id)這樣的寫法是為了防止SQL injection。
ensures that id is properly escaped before being included in the underlying SQL query, thereby avoiding a serious security hole called SQL injection. The id attribute here is just an integer (i.e., self.id, the unique ID of the user), so there is no danger of SQL injection in this case, but always escaping variables injected into SQL statements is a good habit to cultivate.

26. 接下來要開始用partial

27. 在首頁的地方，<%= render 'shared/feed' %> 將顯示_feed.html.erb這個partial。

28. _feed.html.erb這個partial，又會顯示@feed_items這個變數，因為這個變數的class是Micropost，所以又會自動去找_micropost.html.erb這個partial。

Here Rails knows to call the micropost partial because each element of @feed_items has class Micropost. This causes Rails to look for a partial with the corresponding name in the views directory of the given resource:app/views/microposts/_micropost.html.erb

29. 如果送出micropost失敗的話，會break。如果輸入一個空的rray好像也沒用。
At this point, creating a new micropost works as expected, as seen in Figure 11.15. There is one subtlety, though: on failed micropost submission, the Home page expects an @feed_items instance variable, so failed submissions currently break. The easiest solution is to suppress the feed entirely by assigning it an empty array, as shown in Listing 11.48. (Unfortunately, returning a paginated feed doesn’t work in this case. Implement it and click on a pagination link to see why.)

30. <%= render @feed_items %><%= render @microposts %>，這邊的@變數裡面應該都有複數的東西，可是為什麼不必用到each？
原來在Ch9的地方有講到：
9.3.5 Partial refactoring

Here Rails infers that @users is a list of User objects; moreover, when called with a collection of users, Rails automatically iterates through them and renders each one with the _user.html.erb partial. The result is the impressively compact code in Listing 9.48.
雖然Rails會把@user當作User的列表，一個集合，但是在patial的情況下，他會一個一個顯示出來。

31. 點了delete之後，micropost的id會被送到Micropost Controllerdestroy method去。
因為有設before_action的關係，他會先去執行correct_user method
@micropost = current_user.microposts.find_by(id: params[:id])
這邊的id: params[:id]micropost的id
we’ll find the micropost through the association, which will automatically fail if a user tries to delete another user’s micropost. We’ll put the resulting find inside a correct_user before filter, which checks that the current user actually has a micropost with the given id. The result appears in Listing 11.50.
假設current_usermicropost中找不到這個id，會return nil(不會跳出錯誤訊息)
(find會有錯誤訊息，find_by會return nil)
find vs find_by vs where
If no record is found, returns nil.

32. request.referrer || root_url
This uses the request.referrer method,11 which is closely related to the request.url variable used in friendly forwarding (Section 9.2.3), and is just the previous URL (in this case, the Home page).12 This is convenient because microposts appear on both the Home page and on the user’s profile page, so by using request.referrer we arrange to redirect back to the page issuing the delete request in both cases. If the referring URL is nil (as is the case inside some tests), Listing 11.50 sets the root_url as the default using the || operator. (Compare to the default options defined in Listing 8.50.)

33. 開始做上傳照片

34. Micropost Model會需要用到下面的gem，把他們都加到Gemfile

• carrierwave gem： 上傳照片
• mini_magick gem：image resizing (Section 11.4.3)
• fog gem： image upload in production (Section 11.4.4)
35. $rails generate uploader Picture：產生image uploader 圖片上傳器。 CarrierWave adds a Rails generator for creating an image uploader, which we’ll use to make an uploader for an image called picture。 36. 要用CarrierWave上傳照片很簡單：在generate之後，記得把名字(這邊是Picture)放到相對應的Model(這邊是Microposts)去就好了，記得要設成String Images uploaded with CarrierWave should be associated with a corresponding attribute in an Active Record model, which simply contains the name of the image file in a string field. The resulting augmented data model for microposts appears in Figure 11.19. To add the required picture attribute to the Micropost model, we generate a migration and migrate the development database: 37. 然後要加上這行：mount_uploader :picture, PictureUploader，才有辦法把image跟model連接起來。 The way to tell CarrierWave to associate the image with a model is to use the mount_uploader method, which takes as arguments a symbol representing the attribute and the class name of the generated uploader: (Here PictureUploader is defined in the file picture_uploader.rb, which we’ll start editing in Section 11.4.2, but for now the generated default is fine.) Adding the uploader to the Micropost model gives the code shown in Listing 11.56. 38. html: { multipart: true } ：in the arguments to form_for, which is necessary for file uploads. <%= f.file_field :picture %>： To include the uploader on the Home page 39. image_tag helper可以叫出來照片。 picture? boolean method 是CarrierWave跟據attribute的名字自動產生的method。 Once the image has been uploaded, we can render it using the image_tag helper in the micropost partial, as shown in Listing 11.59. Notice the use of the picture? boolean method to prevent displaying an image tag when there isn’t an image. This method is created automatically by CarrierWave based on the name of the image attribute. The result of making a successful submission by hand appears in Figure 11.20. Writing an automated test for image upload is left as an exercise (Section 11.6). 40. 開始限制上傳的照片的格式跟尺寸，在伺服器端跟瀏覽器端都需要做設定 41. 伺服器端：限制上傳檔案的類型：picture_uploader.rb 42. 伺服器端：尺寸：Micropost model，size validation不是內建的，所以要自己寫 43. 用戶端：有兩個 類型：<%= f.file_field :picture, accept: 'image/jpeg,image/gif,image/png' %> 尺寸： 44. 把Query放在最下面 45. ImageMagick: 變更上傳圖檔的尺寸 46. MiniMagickCarrierWavemodule，是用來操控ImageMagick的介面 47. 做一下比較： MiniMagick documentation 這邊的MyUploader後面是CarrierWave::Uploader::Base 這邊是不能超過200X200 CarrierWave documentation on MiniMagick 這邊的AvatarUploader的後面也是CarrierWave::Uploader::Base 這邊是要放大到200X200 這邊的存檔的地方是在本地端的資料夾 48. fog把上傳的存在雲端 : Configuring the image uploader for production. over 2 years ago ## ROR TUTORIAL (3RD ED.) Ch10 Account activation and password reset 重點：Action Mailer library 重點：boolean要從false變成true，可以用update_attribute => Listing 10.29: app/controllers/account_activations_controller.rb 重點：參考self的解釋：When to use self in Model? self Ruby當中的class method和instance method差在哪？ [rails筆記] ruby 觀念小整理 1. Account activation：和passwords (Section 8.2) 跟 remember tokens (Section 8.4)的作法很相似。 2. account activations，不需要用到model (Active Record) (sessions也不用)，所以可以直接加在User Model裡面。resources :account_activations, only: [:edit] As with sessions (Section 8.1), we’ll model account activations as a resource even though they won’t be associated with an Active Record model. Instead, we’ll include the relevant data (including the activation token and activation status) in the User model. Nevertheless, we’ll interact with account activations via a standard REST URL; because the activation link will be modifying the user’s activation status, we’ll plan to use the edit action. 3. 預設是false add_column :users, :activated, :boolean, default: false 4. 每個user都需要activation，所以要在user被created之前，就需要先產生activation token and activation digest Because every newly signed-up user will require activation, we should assign an activation token and digest to each user object before it’s created. 5. before_save：每次存檔前(包含create跟update)都會啟動； before_create：只有在create之前才會啟動。 A before_save callback is automatically called before the object is saved, which includes both object creation and updates, but in the case of the activation digest we only want the callback to fire when the user is created. This requires a before_create callback, which we’ll define as follows: 6. before_create :create_activation_digestmethod reference：在create新用戶前，會先去找這個method。 This code, called a method reference, arranges for Rails to look for a method called create_activation_digest and run it before creating the user. 7. create_activation_digest只會被User Model用到，所以要放在private下面。 Because the create_activation_digest method itself is only used internally by the User model, there’s no need to expose it to outside users; as we saw in Section 7.3.2, the Ruby way to accomplish this is to use the private keyword: 8. 這邊是借用到8.32的概念 (筆記)因為，activation_token是一個不存在的attribute，所以可以需要用self去新增他，然後new_token這個方法不會用到object，所以他是一個Class method，裡面已經寫好了User.new_token SecureRandom.urlsafe_base64 This code simply reuses the token and digest methods used for the remember token, as we can see by comparing with the remember method from Listing 8.32: 9. 有了user之後，才會有remember token這個功能。 可是，使用activation_token的時候，還沒有正式新增user。 所以兩個寫法不同。 當user註冊的時候，會因為before_create這個功能先去產生activation_token and activation_digest，然後activation_digest會被新增到資料庫裡面去。 The main difference is the use of update_attribute in the latter case. The reason for the difference is that remember tokens and digests are created for users that already exist in the database, whereas the before_create callback happens before the user has been created. As a result of the callback, when a new user is defined with User.new (as in user signup, Listing 7.17), it will automatically get both activation_token and activation_digest attributes; because the latter is associated with a column in the database (Figure 10.1), it will be written automatically when the user is saved. 10. Action Mailer library：$ rails generate mailer UserMailer account_activation password_reset
Mailers跟controller actions很像，會有view。
With the data modeling complete, we’re now ready to add the code needed to send an account activation email. The method is to add a User mailer using the Action Mailer library, which we’ll use in the Users controller create action to send an email with an activation link. Mailers are structured much like controller actions, with email templates defined as views. Our task in this section is to define the mailers and views with links containing the activation token and email address associated with the account to be activated.
Here we’ve generated the necessary account_activation method as well as the password_reset method we’ll need in Section 10.2.
As part of generating the mailer, Rails also generates two view templates for each mailer, one for plain-text email and one for HTML email. For the account activation mailer method, they appear as in Listing 10.6 and Listing 10.7.

As with ordinary views, we can use embedded Ruby to customize the template views, in this case greeting the user by name and including a link to a custom activation link. Our plan is to find the user by email address and then authenticate the activation token, so the link needs to include both the email and the token. Because we’re modeling activations using an Account Activations resource, the token itself can appear as the argument of the named route defined in Listing 10.1:edit_account_activation_url(@user.activation_token, ...)

12. Listing 10.21:新增用戶時，如果user_param獲得通過，@user若是被save，UserMailer則會執行account_activation這個method，會把@user送到account_activation去。

13. Listing 10.11: (這邊的@user是要送到view去用的)

14. Listing 10.12: user_mailer.rb送過來的@user，會被用在新用戶的啟動信裡面。

這邊，應該是會被送到 Listing 10.29: app/controllers/account_activations_controller.rbedit method

15. 開始寫edit前的準備工作：
10.1.3 Activating the account：作法會跟passwords (Listing 8.5)remember tokens (Listing 8.36)類似

不過，這邊是寫死的，所以要改成通用的寫法。

可以用send去改成這樣：

因為是在User Model裡面，所以可以把self省略，又可以變成這樣：
Because we’re inside the user model, we can also omit self, yielding the most idiomatically correct version:

(如果沒有token這個變數，可以放''進去，如Listing 10.27)

16. metaprogramming：用來寫程式的程式
metaprogramming, which is essentially a program that writes a program.

17. send method：送出訊息。
send method, which lets us call a method with a name of our choice by “sending a message” to a given object.

18. authenticated?寫好後，就可以開始寫edit了：
With the authenticated? method as in Listing 10.24, we’re now ready to write an edit action that authenticates the user corresponding to the email address in the params hash. Our test for validity will look like this:if user && !user.activated? && user.authenticated?(:activation, params[:id])
!user.activated?的寫法是要避免已經啟用的account再被啟用ㄧ次。
Note the presence of !user.activated?, which is the extra boolean alluded to above. This prevents our code from activating users who have already been activated, which is important because we’ll be logging in users upon confirmation, and we don’t want to allow attackers who manage to obtain the activation link to log in as the user.
If the user is authenticated according to the booleans above, we need to activate the user and update the activated_at timestamp

19. 新註冊者收到啟用信之後，點選連結，會把activation_tokenemail送回來edit method，如果通過檢驗(authenticated?)，就會把:activatedupdatetrue，順便把啟用時間也補上。

20. 要讓activation實際有用，就要把他放在登入的地方：有啟用過的用戶才能登入。

21. refactor：重構
Eddie: 可以的話，controller 儘量精簡一些，把實作的邏輯藏到別的地方去(例如 model、service object、form object..etc)
With the test in Listing 10.31, we’re ready to refactor a little by moving some of the user manipulation out of the controller and into the model. In particular, we’ll make an activate method to update the user’s activation attributes and a send_activation_email to send the activation email. The extra methods appear in Listing 10.33, and the refactored application code appears in Listing 10.34 and Listing 10.35.
這邊的UserMailer.account_activation(@user).deliver_now可以拿到user model，在model新增一個send_activation_email的method

這邊的user.update_attribute可以拿到user model，在model新增一個activate的method

activate methoduser.update_attribute要把user拿掉，可以改成self，不過self在model內又可以被省略。
We could have switched from user to self, but recall from Section 6.2.5 that self is optional inside the model.

22. 我對self的理解：
等號右邊的self是可以省落的。(self.email = email.downcase)
當在一個model裡面時，如果不想新增一個新的變數的話，左邊就一定要寫self (self.remember_token)
Section 10.1.4(在model裡面可以省略self，update_attribute(:activated, true))跟 Section 6.2.5有點矛盾(左邊的self不可省略，email = email.downcase wouldn’t work.)，
Section 6.2.5：self is optional inside the model.
Section 4.4.2：reverse in the palindrome method
Section 8.4：self is not optional in an assignment:
如果要指定自己的attribute，或是不想新增一個local variable的話，就要記得加self。
不過，只是update_attribute的話，(好像)就不用加self

(We could have switched from user to self, but recall from Section 6.2.5 that self is optional inside the model.)

登入的地方(sessions/new.html.erb)加上"忘記密碼的連結"，
點選後會到一個新的view(views/password_resets/new.html.erb)去輸入email，
系統(controllers/password_resets_controller.rbcreate method)會根據email找出來這個user，然後會產生digest(存在資料庫)跟token(寄給用戶)，之後會寄出一封信，包含一個內含email跟token的連結。當
用戶點連結之後，會將用戶的email跟token傳送回去edit method作檢查(被分拆掉了，可以看第26點)，如果這個用戶是有效的(valid_user)話，就顯示變更密碼的頁面(Figure 10.17)，
戶輸入新密碼(兩次)後，會把新密碼傳回去password_resets_controller.rbupdate method去更新密碼。

24. 點選忘記密碼的連結，會跑到views/password_resets/new.html.erb的頁面。
view裡面是這樣寫的：

這樣的寫法，會把user的email傳回去資料庫，
所以new之後，會跑到create去，先用輸入的email找看看有沒有這個user？
如果有的話，就先為他建一個新的reset_digest，然後寄信給這個user。
（這邊又要先跑到user那邊先寫create_reset_digestsend_password_reset_email

25. 可以參考10.1.2 Account activation mailer method
edit_password_reset_url(@user.reset_token, email: @user.email)
http://example.com/password_resets/3BdBrXeQZSWqFIDRN8cxHA/edit?email=foo%40bar.com
可以想作：
edit_user_url
，會變成：
http://example.com/user/1/edit
這一串亂碼是由new_token產生的，可以當作ID來用。the token will be available in the params hash as params[:id].
（這邊的reset_token好像沒有加密，忘記由new_token產生的亂碼有沒有加密過了，好像reset_digest = 'digest'(reset_token)這裏的'digest'才會把東西做加密）
感覺好像是去修改編號(1)user的個人資料。
(這邊記得要有hidden field，才能把email傳回去controller)

26. 點下去edit_password_reset_url(@user.reset_token, email: @user.email)之後，會回到填寫兩次密碼的地方。兩次密碼輸入之後，會回到update method去做驗證。

27. activation的時候，只有edit method，可是沒有update method，好像是因為他在edit裡面就直接用user.update_attribute(:activated, true)了(Listing 10.29: App/controllers/account_activations_controller.rb)

28. password_reset的時候，只有update method，沒有edit method，好像是因為他把edit裡面需要用到的找到user(get_user method)跟認證user (valid_user)都先用before_action處理過了。

29. 點下去edit_password_reset_url(@user.reset_token, email: @user.email)之後，會回到填寫兩次密碼的地方。兩次密碼輸入之後，會回到update method去做驗證。
然後這邊要考慮四種如果：時間過期，成功更新密碼，更新密碼失敗（無效的密碼），更新密碼失敗（確認欄是空白的）
To define the update action corresponding to the edit action in Listing 10.51, we need to consider four cases: an expired password reset, a successful update, a failed update (due to an invalid password), and a failed update (which initially looks “successful”) due to a blank password and confirmation.

over 2 years ago

## ROR TUTORIAL (3RD ED.) Ch9:Updating, showing, and deleting users

1. authentication ：allows us to identify users of our site: 成為用戶。需要登入才能看見的頁面，會將網友導到登入頁。9.2.1
2. authorization ：lets us control what they can do：用戶可以做些什麼。非經授權可以瀏覽的頁面，將會被導到首頁。9.2.2
3. 防止未登入的網友看網頁：before_action（是before filters的一種）在controller所有的actions執行前會先執行。 Before filters use the before_action command to arrange for a particular method to be called before the given actions3 To require users to be logged in, we define alogged_in_user method and invoke it using before_action :logged_in_user, as shown in Listing 9.12.
4. 9.2.1 要登入才能看到某些頁面：logged_in_user
預設值是只要有before filters，在該controller內的每個action執行之前，都會先執行before filters，除非我們先設定好only這個hash。before_action :logged_in_user, only: [:edit, :update]
By default, before filters apply to every action in a controller, so here we restrict the filter to act only on the :edit and :update actions by passing the appropriate :only options hash.

5. 9.2.2 用戶只能看到自己頁面：correct_user
users should only be allowed to edit their own information.

6. 設定可以訪問該頁面的正確使用者correct_user

7. unless @user == current_user可以變成unless current_user?(@user)

8. 當用戶訪問edit頁面的時候，會先跑before_actioncorrect_user會先抓出來@user，接著跑current_user?(@user)的時候，會把@user送到sessions_helper.rbcurrent_user?(user)去，如果user == current_user是正確的，current_user?(user)會傳true回去correct_user，然後該用戶就可以進去edit page

9. 9.2.3 Friendly forwarding：登入後，會把用戶轉到用戶本來想要去的頁面。
要把本來要去的頁面先存在store_location裡面
In order to forward users to their intended destination, we need to store the location of the requested page somewhere, and then redirect to that location instead of to the default. We accomplish this with a pair of methods, store_location and redirect_back_or, both defined in the Sessions helper (Listing 9.27).

這邊將使用session。按照8.2.1的解釋：Session是Rails內建的方法，session[:user_id] = user.id，這種方式可以把id加密，然後把session[:user_id]存在瀏覽器裡面，以後就可以存取。
所以session[:forwarding_url] = request.url，也是相同的步驟：將所要求的網址存到session裡面去。
最後，要把store_location放到logged_in_user method裡面去：如果沒有logged in，會先儲存本來要去的地方在session，然後顯示請登入的訊息，接著轉到登入頁面去。

10. redirect_back_or(default)method放到sessions_controller.rbcreate去。

11. 9.3：seed the database(9.3.2：faker) + paginate(9.3.3：will_paginate + bootstrap-will_paginate)

12. 用faker gem來新增假用戶 (灌完gem之後，記得要bundle install)，清空資料庫 (reset the database：bundle exec rake db:migrate:reset)和重啟資料庫(invoke the Rake task using db:seed =>bundle exec rake db:seed)

13. create!會在有錯誤的時後跳出例外(exception：主要是為了debug)。
The create! method is just like the create method, except it raises an exception (Section 6.1.4) for an invalid user rather than returning false. This behavior makes debugging easier by avoiding silent errors.
參考：save 與 save! / create 與 create!

其中 save / create，遇到過 validation 時，只會回傳 true 或 false。但有時候我們要 debug 一個表單，有時候一直不知道為何表單為何沒成功一直 false，有時候會使用 save! 或 create! 去 debug。這兩個 method 會 throw ActiveRecord::RecordInvalid exception 中斷程式。明確的告訴你壞在哪邊。

14. 9.3.3：will_paginate + bootstrap-will_paginate

15. 在user的view時，will_paginate會自動找尋@user (在不同的view應該是會找不同的@)@users = User.paginate(page: params[:page])
The will_paginate method is a little magical; inside a users view, it automatically looks for an @users object, and then displays pagination links to access other pages.

16. 9.4.1：設成boolean，就會自動有?的method。 要記得把boolean的預設值設定為default: false
We will identify privileged administrative users with a boolean admin attribute in the User model, which will lead automatically to an admin? boolean method to test for admin status. The resulting data model appears in Figure 9.14.

over 2 years ago

## 新增PROFILE: view/dashboard/profile/new.html.erb

(以後應該在new respond 的地方不用一題一題回答，可以一次送出去很多題，不過就qupid的商業模式好像也沒有必要一次送出去很多題)

Rails form with multiple nested models causes issues with radio groups
2009年的這篇，雖然好像可以，可是實際上也不知道有沒有解出來。

accepts_nested_attributes_for好像只能用在has_many，也可以用在has_many::through上
(參考這篇：accepts_nested_attributes_for with Has-Many-Through Relations)

params:

over 2 years ago

## 回答問題的模式 (後台跟前台)

1. 登入： - 帳號密碼：devise - 個人資訊：has_one :profile，地點、性別、生日 - 準備題：同時送出五題單選題 (暫定使用select_tag) (這邊要參考阿之的解法，記得select_tag要跟controller搭配好，實際作法是這樣：profile/new.html.erb
2. 回答配對問題：點選想要回答的問題，進去個別頁面後，一次回答一個的單選題 (暫定使用check_box_tag) - 有全部未答過問題的index page。(要把SpecialCates的問題排除掉。在個別頁面的地方要檢查一下，如果以前回答過，就應該跳回去index) - 可能要分作價值觀、戀愛觀、金錢觀等分頁：尚未決定 - 可能要分作今日新題目、時事題、特殊題：尚未決定，但應該都是一頁回答一個問題。
3. 用戶後台： - 可以看到自己已經回答過的問題，然後可以一次edit一個問題的答案。 - 可以看到自己的profile，然後決定要不要edit自己的準備題。(profile edit的code可以用profile new的code)
4. 其他用戶前台(User show page)：可以看到其他用戶回答過的問題與答案。 - 如果自己有回答過的話，可以看到自己的答案，也可以選擇要不要換答案。 - 如果自己沒有回答過的話，可以選擇要不要回答。 - 可以看到其他用戶的profile跟準備題 (不過這邊不能重複使用profile new的code) (這邊還沒弄好)

http://guides.rubyonrails.org/form_helpers.html
3.3 Option Tags from a Collection of Arbitrary Objects

over 2 years ago

## 來紀錄一下我的後台是怎麼新增Cate(類別), Issue(題目), Option(選項)。

(has_many, through:比HABTM好的理由看這裡)

• 第一種做法：

• 第二種做法：等於是最簡單的做法加上第一種做法

• 一個題目有兩個（或以上的）category columns(attributes)
• 一個可以叫ordinary category，一個可以叫special category
• 也是可以選擇要不要用{:multiple => true}

1. 舊的：題目只會屬於一個類別，所以寫成has_many/belongs_to。

重要：select的寫法：(這邊可能寫錯了，怎麼會沒有f.)
<%= select('issue', 'cate_id', Cate.all.collect {|p| [ p.name, p.id ] }, { include_blank: true }, {:class =>"form-control"})%>

注意：這邊是:cate_id，因為只有一個cate_id會傳出去。

2. 第一種做法：要新增一個cate_issue.rb，然後

注意：這邊記得要改成:cate_ids => []，因為會傳出去很多個cate ids

<%= label_tag "類別：" %> <%= f.select :cate_ids, Cate.all.collect {|p| [ p.name, p.id ] }, { }, {:class =>"form-control", :multiple => true} %>

3. 第二種做法：要新增一個cate_issue.rb（應該要改個名字比較好，不過還沒想到）跟另一個category的名字。
記得：改成OrdinaryCategory.rb，SpecialCategory.rb，Issue.rb，CateIssue.rb (先保留Cate.rb)
記得：改routes，要在cateissue table 新增ordinary_cate_id 跟special_cate_id

注意：這邊記得要改成:cate_ids => []，因為會傳出去很多個cate ids

注意：這邊寫法要注意

over 2 years ago