Ruby on Rails поток данных ActiveRecord - PullRequest
0 голосов
/ 01 июня 2018

В настоящее время я пытаюсь создать приложение, которое работает примерно так: Trello .У меня есть users, который может создать boards.Каждый пользователь может иметь различный role в зависимости от того, на какой доске он находится.Поскольку я довольно новичок в Rails, я просто хочу убедиться, что я следую «Rails way» и лучшим практикам.Вот моя схема:

create_table "boards", force: :cascade do |t|
    t.string "title"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
  end

  create_table "user_boards", force: :cascade do |t|
    t.integer "user_id"
    t.integer "board_id"
    t.integer "role"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
  end

  create_table "users", force: :cascade do |t|
    t.string "name"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
    t.string "email", default: "", null: false
    t.string "encrypted_password", default: "", null: false
    t.string "reset_password_token"
    t.datetime "reset_password_sent_at"
    t.datetime "remember_created_at"
    t.integer "sign_in_count", default: 0, null: false
    t.datetime "current_sign_in_at"
    t.datetime "last_sign_in_at"
    t.inet "current_sign_in_ip"
    t.inet "last_sign_in_ip"
    t.index ["email"], name: "index_users_on_email", unique: true
    t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
  end

  add_foreign_key "lists", "boards"

Как видите, я добавил атрибут role в таблицу соединений UserBoard.A User has_many Boards & Board has_many Users оба through: UserBoard.В зависимости от User & Board они могут иметь различную role.

user_board.rb

class UserBoard < ApplicationRecord
  belongs_to :user
  belongs_to :board
  enum role: { admin: 0, member: 1 }
end

user.rb

class User < ApplicationRecord
  has_many :user_boards
  has_many :boards, through: :user_boards
  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable and :omniauthable
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :trackable, :validatable
  validates :name, presence: true, length: { maximum: 50 }
  validates :email, presence: true
end

..rb

class Board < ApplicationRecord
  has_many :user_boards
  has_many :users, through: :user_boards
  has_many :lists, dependent: :destroy
  include AssociateUsersToBoards

  def self.assign_board_to_user(user, board)
    AssociateUsersToBoards.build_association(user, board)
  end
end

Я просто пытаюсь понять, является ли это лучшим способом справиться с этим, и есть ли лучший способ настроить его так, чтобы мои запросы и обновления могли быть немного чище.Прямо сейчас, когда User создает Board, вы можете видеть, что я использую функцию ActiveRecord:create.Причина, по которой я использую create, заключается в том, что когда я пытаюсь использовать new или build, связь в таблице соединений не создается.Мне кажется неправильным, что я не смог бы выполнить current_user.boards.new(board_params) или current_user.boards.build(board_params):

def create
  @board = current_user.boards.new(board_params)

  respond_to do |format|
    if current_user.save
      format.html { redirect_to @board, notice: 'Board was successfully created.' }
      format.json { render :show, status: :created, location: @board }
    else
      format.html { render :new }
      format.json { render json: @board.errors, status: :unprocessable_entity }
    end
  end
end

Но я также хочу установить role на admin .. Единственный способ, которым яМожно подумать, что это current_user.user_boards.find_by(board_id:@board).update_attribute(:role, 'admin') после того, как я сохранил свою запись в моем board#create действии.Этот запрос заставляет меня хотеть рвоты, и я не могу поверить, что нет лучшего подхода.

Мои board_params очень просты и допускают простой заголовок:

def board_params
  params.require(:board).permit(:title)
end

РЕДАКТИРОВАТЬ


Я также хотел добавить форму, которую я использую для отправки board, чтобы убедиться, что в этом нет ничего плохого:

<div class="modal-body">
  <%= form_with(model: board, local: true) do |form| %>
    <% if board.errors.any? %>
      <div id="error_explanation">
        <h2><%= pluralize(board.errors.count, "error") %> prohibited this board from being saved:</h2>

        <ul>
          <% board.errors.full_messages.each do |message| %>
            <li><%= message %></li>
          <% end %>
        </ul>
      </div>
    <% end %>

    <div class="form-group">
      <%= form.label :title %><br/>
      <%= form.text_field :title, autofocus: true, class: 'form-control' %>
    </div>

    <div class="actions">
      <%= form.submit 'Create Board', class: 'btn btn-small btn-success btn-block' %>
    </div>
  <% end %>
</div>

Все предложения, советы и конструктивная критика очень ценятся, так как я стараюсь больше узнавать / знакомиться с Ruby language & Rails framework.

Ответы [ 2 ]

0 голосов
/ 02 июня 2018

Итак, я нашел довольно простой и элегантный способ обработки автозаполнения пользователей role при создании доски.Вот мое решение:

class UserBoard < ApplicationRecord
  belongs_to :user
  belongs_to :board
  enum role: { admin: 0, member: 1 }
  before_create :set_admin

  private

  def set_admin
    self.role = 'admin'
  end
end

Я просто добавил метод обратного вызова before_create, который устанавливает роль в записи таблицы присоединения равной admin перед созданием каждой записи.Затем его можно соответствующим образом скорректировать.

Я сделал и все еще могу иметь некоторую путаницу вокруг моего board#create метода.Я провел некоторое исследование и думаю, что могу объяснить, почему решение @jvillian для создания ассоциации user board не будет работать.Таким образом, это был предоставленный метод для создания ассоциации:

  @board = current_user.boards.new(board_params)
    if @board.save

Однако здесь произойдет то, что будет создана запись Board, вы даже можете увидеть, как она была «связана» с пользователемкогда ты побежал current_user.boards.Но запись в таблице соединений не будет создана.Я прочитал, что в случае ассоциации has_many дочерний элемент сохраняется при сохранении родительского элемента , если child.new_record?возвращает значение true (дочерний элемент еще не был сохранен в БД), или необходимо обновить столбец foreign_key.Таким образом:

  1. Добавление объекта к ассоциации на сохраненном родителе (current_user.save) действительно сохраняет нового дочернего элемента.
  2. Добавление объекта к ассоциации на несохраненном родителе (@board.save) не делаетсохранить значение внешнего ключа (запись таблицы объединения не создана)
  3. Если несохраненный родительский объект сохраняется и содержит несколько дочерних объектов в кеше ассоциации, эти объекты сохраняются для обновления foreign_key.

Таким образом, в этом случае current_user (объект пользователя) является родительским и имеет ассоциацию @board, которая кэшируется, что затем обновляет foreign_key и создает запись в таблице соединений.С другой стороны, сохранение @board сохранит новый объект Board и обновит кешированный Board объект, назначенный на current_user.boards, но НЕ создает чужой ключ.

Надеюсь, это имеет смыслеще важнее правильно.Пожалуйста, дайте мне знать иначе.Я хочу убедиться, что у меня есть правильное понимание.

0 голосов
/ 01 июня 2018

Вы не показываете board_params, но, возможно, оно должно выглядеть примерно так:

def board_params
  params.require(:board).permit(:something, :whatever_else).merge!(role: :admin)
end

Затем выполните что-то вроде:

def create
  @board = current_user.boards.new(board_params)

  respond_to do |format|
    if @board.save
      format.html { redirect_to @board, notice: 'Board was successfully created.' }
      format.json { render :show, status: :created, location: @board }
    else
      format.html { render :new }
      format.json { render json: @board.errors, status: :unprocessable_entity }
    end
  end
end

Это должно создать новыйдоска с user_id и role установлена ​​правильно.

Кстати, лично я предпочитаю:

class UserBoard < ApplicationRecord
  belongs_to :user
  belongs_to :board
  enum role: {
    admin:  0,
    member: 1
  }
end

Так что мне не нужно беспокоиться о позиции enum в массивахкак обсуждено в документах :

Обратите внимание, что при использовании массива неявное отображение значений в целые числа базы данных получается из порядка, в котором значения появляются в массиве.В этом примере: active отображается на 0 как первый элемент, а: archived отображается на 1. В общем случае i-й элемент отображается в базе данных на i-1.

Следовательно,как только значение добавляется в массив enum, его позиция в массиве должна сохраняться, а новые значения должны добавляться только в конец массива.Для удаления неиспользуемых значений следует использовать явный синтаксис хеша.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...