ASTRO Camp 11th
      • Sharing URL Link copied
      • /edit
      • View mode
        • Edit mode
        • View mode
        • Book mode
        • Slide mode
        Edit mode View mode Book mode Slide mode
      • Customize slides
      • Note Permission
      • Read
        • Owners
        • Signed-in users
        • Everyone
        Owners Signed-in users Everyone
      • Write
        • Owners
        • Signed-in users
        • Everyone
        Owners Signed-in users Everyone
      • Engagement control Commenting, Suggest edit, Emoji Reply
    • Invite by email
      Invitee

      This note has no invitees

    • Publish Note

      Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

      Your note will be visible on your profile and discoverable by anyone.
      Your note is now live.
      This note is visible on your profile and discoverable online.
      Everyone on the web can find and read all notes of this public team.
      See published notes
      Unpublish note
      Please check the box to agree to the Community Guidelines.
      View profile
    • Commenting
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
      • Everyone
    • Suggest edit
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
    • Emoji Reply
    • Enable
    • Versions and GitHub Sync
    • Note settings
    • Note Insights New
    • Engagement control
    • Make a copy
    • Transfer ownership
    • Delete this note
    • Insert from template
    • Import from
      • Dropbox
      • Google Drive
      • Gist
      • Clipboard
    • Export to
      • Dropbox
      • Google Drive
      • Gist
    • Download
      • Markdown
      • HTML
      • Raw HTML
Menu Note settings Note Insights Versions and GitHub Sync Sharing URL Help
Menu
Options
Engagement control Make a copy Transfer ownership Delete this note
Import from
Dropbox Google Drive Gist Clipboard
Export to
Dropbox Google Drive Gist
Download
Markdown HTML Raw HTML
Back
Sharing URL Link copied
/edit
View mode
  • Edit mode
  • View mode
  • Book mode
  • Slide mode
Edit mode View mode Book mode Slide mode
Customize slides
Note Permission
Read
Owners
  • Owners
  • Signed-in users
  • Everyone
Owners Signed-in users Everyone
Write
Owners
  • Owners
  • Signed-in users
  • Everyone
Owners Signed-in users Everyone
Engagement control Commenting, Suggest edit, Emoji Reply
  • Invite by email
    Invitee

    This note has no invitees

  • Publish Note

    Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

    Your note will be visible on your profile and discoverable by anyone.
    Your note is now live.
    This note is visible on your profile and discoverable online.
    Everyone on the web can find and read all notes of this public team.
    See published notes
    Unpublish note
    Please check the box to agree to the Community Guidelines.
    View profile
    Engagement control
    Commenting
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    • Everyone
    Suggest edit
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    Emoji Reply
    Enable
    Import from Dropbox Google Drive Gist Clipboard
       Owned this note    Owned this note      
    Published Linked with GitHub
    • Any changes
      Be notified of any changes
    • Mention me
      Be notified of mention me
    • Unsubscribe
    # 20220810 Rails 無名小站實作 (Rich) JS處理留言板、按讚 ###### tags: `Ruby` `Rails` ### SSR Server-Side Rendering 蝦皮與OB的差別: 蝦皮載入時,框框就會在了。 OB則是會將畫面撐開。 pchome是SSR ## 使用JS處理comment action預設為找同名的view 其副檔名不一定要是html.erb ,也可以是js.erb XXX.js.erb 可以在js放ruby code <%= form_with model: {MODEL}, <mark>local: false</mark> do |f| %> <% end%> `<form ...... `<mark>data-remote="true"</mark>` ></form>` 之前我們是用轉址的方式去處理, 在form_with設定local :false之後, 我們原本打過去類型是html, 現在打過去在回傳的類型會變成js, 會找到js.erb檔案, 就可以做到前後端分離。 ![](https://i.imgur.com/xwwwNPa.png) 用這樣的方式會浪費記憶體空間 不要在迴圈裡面做render 效能不好 所以我們可以做的是用[render collection](https://guides.rubyonrails.org/layouts_and_rendering.html#rendering-collections)來改善 ----- ### 補充: 完整寫法 ```ruby= <%= render partial: "comments/comment", collection: @comments, as: :comment %> ``` 若滿足幾個條件便可寫簡化版 1. partial_view 剛好在 views/comments/_comment.html.erb 2. 區域變數為 comment 簡化版如下 ```ruby= <%= render @comments %> ``` --- _comment.html.erb 不只可以給 comment.html.erb, 也可以給 comment.js.erb 使用 ## 按讚 ![](https://i.imgur.com/Mx60iKw.png) https://drawsql.app/teams/kerkers-team/diagrams/first-diagram - user跟LikeArticle多對多 - article跟LikeArticle多對多 為article新增按讚功能, 會需要第三方table LikeArticle, 同時紀錄user id 跟article id model LikeArticle ```shell! $rails g model LikeArticle user:belongs_to article:belongs_to ``` 要在user.rb裡面加 ```ruby has_many :like_articles has_many :liked_articles, through: :like_articles, source: :article ``` article.rb裡面加 ```ruby has_many :like_articles has_many :users, through: :like_articles ``` ### 資料表自我參照 self-reference 舉例: 主管跟員工都是員工, 所以只有一個員工的table就可以 留言跟回覆都是留言, 所以只有一個留言的table就可以 ### namespace 想url做路徑: >**api**/articles/:id/like ```ruby= namespace :api do resources :article, only:[] do member do post: like end end end ``` ```shell rails g controller api/articles ``` 設計api給別人用的時候,可以設計版1版2(v1, v2) 如果你要加功能時,就可以使用這些版號去區別新舊版, 釋出新功能時舊版本依舊可以使用, 舊的不會壞, 使用者經驗比較好 類似版本控制 > api/v1/articles/:id/like ```ruby= namespace :api do namespace :v1 do resources :article, only:[] do member do post: like end end end end ``` rails g controller api/v1/articles ### 做按讚的按鈕 到app>javascript>packs>application.js寫js (全區都會被執行) ![](https://i.imgur.com/6kchYGL.png) 把import "channels"註解掉 因為這是做即時通訊功能用的 #### webpack 打包 加速效能 終端機下指令開啟功能 $ bin/webpack-dev-server 專門打包 (在資料夾bin 之下) rails 不擅長打包,所以交給別人來做吧! webpack -> 專門打包前端的工具, 有live reload的效果 VS code存檔畫面就會自動更新不用重新整理,可以加速執行效能 #### 安裝套件囉~~ <3 Foreman(可以雙開webpack 跟 rails server) https://rubygems.org/gems/foreman/ ```shell= $ gem 'foreman', '~> 0.87.2' $ bundle add foreman ``` 開發用得到,但上線時用不到,所以將他放在Gemfile`development` 修改 gemfile 後: ```shell= $ bundle install ``` ![](https://i.imgur.com/jZb6N7o.png) 所以下一次就不用在用rails s 避免部屬heroku會有問題蓋過原生Profile - 改檔名Procfile => Procfile.dev ![](https://i.imgur.com/FBeHOKU.png) ```shell= $ foreman s -f ``` 不打-f 的話,預設會去找procfile, 就會啟動失敗 但可以自己做一個`.foreman`檔 ```yaml= procfile: Procfile.dev ``` 這樣的話只要啟動以下 就沒問題了 ```shell= $ foreman s ``` 題外話: **不要被副檔名騙了,重點是裡面寫了什麼** ### 監聽按鈕點擊事件 還記得DOMContentLoaded嗎?沒有的話抓不到按鈕~ ```javascript= document.addEventListener("DOMContentLoaded", () => { // 監聽按鈕點擊事件 }) ``` ### 安裝套件囉~~ <3 Stimulus 可以導入ruby概念執行JS,簡化原生JS需要抓東西監聽的小框架 ### [<img src="https://raw.githubusercontent.com/hotwired/stimulus/main/assets/logo.svg?sanitize=true" width="24" height="24" alt="Stimulus"> Stimulus](https://stimulus.hotwired.dev/) ![](https://i.imgur.com/IN2oE4N.png =600x) 可以先用rails --help去找看看有沒有可以裝的套件 ```shell= $ rails webpacker:install:stimulus ``` 安裝完套件Javascript資料夾會多一個controllers資料夾 修改一下hello_controller.js(可自行改名) ```javascript= export default class extends Controller { connect(){ console.log(123); } } ``` 在show.html.erb加上有data-controller的section把button包起來 ```ruby= <section data-controller="hello"> <button id="likeBtn">☆</button> </section> ``` 修改一下,把hello改成like ```ruby= <section data-controller="like"> <button id="likeBtn" data-action="click->like#like_article">☆</button> </section> ``` 再修改一下hello_controller.js 名字改成like_controller.js ```javascript= export default class extends Controller { like_article(){ console.log("HI"); } } ``` 好多like喔~~所以命名很重要啊!! :::warning 後端使用: bundle add XXX => Gemfile 前端使用: yarn add XXX => node_modules ::: ### 使用axios套件 `$ yarn add axios` >Axios is a promise-based HTTP Client for node.js and the browser. It is isomorphic (= it can run in the browser and nodejs with the same codebase). 加上import axios from "axios" (前面的axios可自己改名,但後續引用也要跟著改) ```javascript= import { Controller } from "stimulus" import axios from "axios" export default class extends Controller { like_article(){ console.log('hi'); const token = document.querySelector("meta[name=csrf-token]").content axios.default.headers.common["X-CSRF-Token"] = token axios.post("/api/v1/articles/6/like").then((resp) => { console.log(resp.data) }) } } ``` 取得Token ```javascript= document.querySelector("meta[name=csrf-token]").content ``` 可以整理一下JS,在javascript的資料夾新增lib資料夾,再建一個http資料夾,再新建一個client.js javascript/lib/http/client.js 增加的檔名可以自己取 把塞token的處理放到client.js裡面,後續其他地方要使用可以再import ```javascript import ax from "axios"; const metaToken = document.querySelector("meta[name=csrf-token]") if (metaToken) { const token = metaToken.content ax.defaults.headers.common["X-CSRF-Token"] = token } export default ax ``` 外面導出後,datacontroller加上 data-article-id,才可以讓按鈕按下找到id編號 ```ruby # 兩個like都是指controller,like_article則是呼叫controller內的JS function <section data-controller="like" data-article-id="<%= @article.id %>"> <button class="likeBtn" data-action="click->like#like_article">☆</button> </section> ``` 回去透過axios產生的controller,打API -> POST /api/v1/articles/:id/like ```javascript import { Controller } from "stimulus" import ax from "lib/http/client" export default class extends Controller { like_article() { // 用this.element可以找到data controller控制的元素 //這裡的this是指like_controller.js const articleID = this.element.dataset.articleId; // 打API -> POST /api/v1/articles/:id/like ax.post(`/api/v1/articles/${articleID}/like`).then((resp) => { console.log(resp.data); }) } } ``` Ruby沒辦法把東西送給JS 所以用HTML當作媒介 ![](https://i.imgur.com/SHLz4r8.png)

    Import from clipboard

    Paste your markdown or webpage here...

    Advanced permission required

    Your current role can only read. Ask the system administrator to acquire write and comment permission.

    This team is disabled

    Sorry, this team is disabled. You can't edit this note.

    This note is locked

    Sorry, only owner can edit this note.

    Reach the limit

    Sorry, you've reached the max length this note can be.
    Please reduce the content or divide it to more notes, thank you!

    Import from Gist

    Import from Snippet

    or

    Export to Snippet

    Are you sure?

    Do you really want to delete this note?
    All users will lose their connection.

    Create a note from template

    Create a note from template

    Oops...
    This template has been removed or transferred.
    Upgrade
    All
    • All
    • Team
    No template.

    Create a template

    Upgrade

    Delete template

    Do you really want to delete this template?
    Turn this template into a regular note and keep its content, versions, and comments.

    This page need refresh

    You have an incompatible client version.
    Refresh to update.
    New version available!
    See releases notes here
    Refresh to enjoy new features.
    Your user state has changed.
    Refresh to load new user state.

    Sign in

    Forgot password

    or

    By clicking below, you agree to our terms of service.

    Sign in via Facebook Sign in via Twitter Sign in via GitHub Sign in via Dropbox Sign in with Wallet
    Wallet ( )
    Connect another wallet

    New to HackMD? Sign up

    Help

    • English
    • 中文
    • Français
    • Deutsch
    • 日本語
    • Español
    • Català
    • Ελληνικά
    • Português
    • italiano
    • Türkçe
    • Русский
    • Nederlands
    • hrvatski jezik
    • język polski
    • Українська
    • हिन्दी
    • svenska
    • Esperanto
    • dansk

    Documents

    Help & Tutorial

    How to use Book mode

    Slide Example

    API Docs

    Edit in VSCode

    Install browser extension

    Contacts

    Feedback

    Discord

    Send us email

    Resources

    Releases

    Pricing

    Blog

    Policy

    Terms

    Privacy

    Cheatsheet

    Syntax Example Reference
    # Header Header 基本排版
    - Unordered List
    • Unordered List
    1. Ordered List
    1. Ordered List
    - [ ] Todo List
    • Todo List
    > Blockquote
    Blockquote
    **Bold font** Bold font
    *Italics font* Italics font
    ~~Strikethrough~~ Strikethrough
    19^th^ 19th
    H~2~O H2O
    ++Inserted text++ Inserted text
    ==Marked text== Marked text
    [link text](https:// "title") Link
    ![image alt](https:// "title") Image
    `Code` Code 在筆記中貼入程式碼
    ```javascript
    var i = 0;
    ```
    var i = 0;
    :smile: :smile: Emoji list
    {%youtube youtube_id %} Externals
    $L^aT_eX$ LaTeX
    :::info
    This is a alert area.
    :::

    This is a alert area.

    Versions and GitHub Sync
    Get Full History Access

    • Edit version name
    • Delete

    revision author avatar     named on  

    More Less

    Note content is identical to the latest version.
    Compare
      Choose a version
      No search result
      Version not found
    Sign in to link this note to GitHub
    Learn more
    This note is not linked with GitHub
     

    Feedback

    Submission failed, please try again

    Thanks for your support.

    On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?

    Please give us some advice and help us improve HackMD.

     

    Thanks for your feedback

    Remove version name

    Do you want to remove this version name and description?

    Transfer ownership

    Transfer to
      Warning: is a public team. If you transfer note to this team, everyone on the web can find and read this note.

        Link with GitHub

        Please authorize HackMD on GitHub
        • Please sign in to GitHub and install the HackMD app on your GitHub repo.
        • HackMD links with GitHub through a GitHub App. You can choose which repo to install our App.
        Learn more  Sign in to GitHub

        Push the note to GitHub Push to GitHub Pull a file from GitHub

          Authorize again
         

        Choose which file to push to

        Select repo
        Refresh Authorize more repos
        Select branch
        Select file
        Select branch
        Choose version(s) to push
        • Save a new version and push
        • Choose from existing versions
        Include title and tags
        Available push count

        Pull from GitHub

         
        File from GitHub
        File from HackMD

        GitHub Link Settings

        File linked

        Linked by
        File path
        Last synced branch
        Available push count

        Danger Zone

        Unlink
        You will no longer receive notification when GitHub file changes after unlink.

        Syncing

        Push failed

        Push successfully