Rails 5 полный курс и модуль на пользователя при нажатии - PullRequest
0 голосов
/ 13 сентября 2018

Итак, у меня есть три уровня функциональности: курсы, модули курса и упражнения курса.

Однако я хочу реализовать функциональность, позволяющую пользователям отмечать модуль курса, когда они его заканчивают, у меня уже была эта работа ранее, однако это означало, что модули завершены для всех пользователей, которые не являются желаемый результат я хочу.

Итак, я попробовал следующее, где я установил две новые таблицы, одну для courses_users и course_modules_users, чтобы я мог записывать пользователей курса и добавлять запись, содержащую идентификатор пользователя, идентификатор курса, идентификатор модуля и т. Д. поэтому он полностью уникален для этого пользователя (поэтому он не делает его полным для всех пользователей)

Вот схема относительно курсов, модулей курса и упражнений:

ActiveRecord::Schema.define(version: 2018_09_12_115008) do

  # These are extensions that must be enabled in order to support this database
  enable_extension "plpgsql"

  create_table "course_exercises", force: :cascade do |t|
    t.string "title"
    t.text "description"
    t.string "video"
    t.integer "course_module_id"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
    t.string "slug"
    t.index ["course_module_id"], name: "index_course_exercises_on_course_module_id"
    t.index ["slug"], name: "index_course_exercises_on_slug", unique: true
  end

  create_table "course_modules", force: :cascade do |t|
    t.string "title"
    t.integer "course_id"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
    t.string "slug"
    t.index ["course_id"], name: "index_course_modules_on_course_id"
    t.index ["slug"], name: "index_course_modules_on_slug", unique: true
  end

  create_table "course_modules_users", force: :cascade do |t|
    t.integer "course_module_id"
    t.integer "user_id"
    t.boolean "complete"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
    t.index ["course_module_id"], name: "index_course_modules_users_on_course_module_id"
    t.index ["user_id"], name: "index_course_modules_users_on_user_id"
  end

  create_table "courses", force: :cascade do |t|
    t.string "title"
    t.text "summary"
    t.text "description"
    t.string "trailer"
    t.integer "price"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
    t.string "slug"
    t.index ["slug"], name: "index_courses_on_slug", unique: true
  end

  create_table "courses_users", force: :cascade do |t|
    t.integer "course_id"
    t.integer "user_id"
    t.boolean "complete"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
    t.index ["course_id"], name: "index_courses_users_on_course_id"
    t.index ["user_id"], name: "index_courses_users_on_user_id"
  end
end

Вот как выглядят новые таблицы:

image image

Для моделей я сделал следующее:

course.rb

class Course < ApplicationRecord
  extend FriendlyId
  friendly_id :title, use: :slugged

  has_many :course_modules

  validates :title, :summary, :description, :trailer, :price, presence: true

  def complete?
  end
end

course_exercise.rb

class CourseExercise < ApplicationRecord
  extend FriendlyId
  friendly_id :title, use: :slugged

  belongs_to :course_module

  validates :title, :description, :video, :course_module_id, presence: true
end

course_module.rb

class CourseModule < ApplicationRecord
  extend FriendlyId
  friendly_id :title, use: :slugged

  belongs_to :course
  has_many :course_exercises

  validates :title, :course_id, presence: true

  scope :completed, -> { where(complete: true) }
  after_save :update_course, if: :complete?

  def complete?
  end

  private

  def update_course
    course.complete! if course.course_modules.all?(&:complete?)
  end
end

course_modules_user.rb

class CourseModulesUser < ApplicationRecord
  belongs_to :course_module
  belongs_to :user
end

courses_user.rb

class CoursesUser < ApplicationRecord
  belongs_to :course
  belongs_to :user
end

Для контроллеров я сделал следующее:

курсы / show.html.erb

<% if user_signed_in? %>
  <section class="pt-4 px-8">
    <section class="flex flex-wrap justify-between">
      <h3 class="font-normal text-grey-dark mb-4 py-2">
        <% if current_user.isAdmin? %>
          <%= @course.title %>
        <% else %>
          <%= @course.title %> Modules
        <% end %>
      </h3>
      <%= render 'layouts/dashboard/account' %>
    </section>
  </section>

  <section class="px-8">
    <% if Order.exists?(user_id: current_user.id, course_id: @course.id) %>
      <% @course_modules.each do |course_module| %>
        <section class="accordion-toggle">
          <section class="w-full sm:pr-4 pb-4">
            <section class="rounded shadow bg-grey-lighter border-b">
              <section class="flex justify-between px-6 p-4">
                <section class="flex items-center px-6 text-grey-darker">
                  <section class="font-bold text-base">
                    <%= course_module.title %>
                  </section>
                </section>

                <section class="flex items-center">
                  <% if user_signed_in? %>
                    <% if current_user.isAdmin? %>
                      <%= link_to "Edit", edit_course_module_path(course_module), class: "text-base text-grey-dark hover:text-darker px-4 py-2 border-2 border-grey leading-none no-underline hover:border-2 hover:border-grey-dark" %>
                    <% else %>
                      <% if course_module.complete? %>
                        <i class="fas fa-check text-green float-left mr-1"></i>
                        <span class="text-xs mr-2">Completed</span>
                      <% else %>
                        <%= link_to complete_course_module_path(course_module), method: :put do %>
                          <i class="fas fa-check text-grey-darkest float-left mr-2"></i>
                        <% end %>
                      <% end %>
                      <i class="flex items-center fal fa-angle-up"></i>
                    <% end %>
                  <% end %>
                </section>
              </section>
            </section>

            <section class="accordion-items hidden">
              <% course_module.course_exercises.each do |exercise| %>
                <section class="w-full">
                  <section class="rounded shadow bg-grey-lighter border-b">
                    <section class="flex justify-between px-6 p-4">
                      <section class="flex items-center px-6 text-grey-darker">
                        <section class="font-bold text-base pl-4">
                          - <%= exercise.title %>
                        </section>
                      </section>

                      <section>
                        <% if user_signed_in? %>
                          <% if current_user.isAdmin? %>
                            <%= link_to "Edit", edit_course_exercise_path(exercise), class: "text-base text-grey-dark hover:text-darker px-4 py-2 border-2 border-grey leading-none no-underline hover:border-2 hover:border-grey-dark" %>
                          <% else %>
                            <%= link_to "View Exercise", exercise, class: "text-base text-grey-dark hover:text-darker px-4 py-2 border-2 border-grey leading-none no-underline hover:border-2 hover:border-grey-dark" %>
                          <% end %>
                        <% end %>
                      </section>
                    </section>
                  </section>
                </section>
              <% end %>
            </section>
          </section>
        </section>
      <% end %>
    <% else %>
      <h3>You have not bought this course!</h3>

      <%= form_with(url: '/payments/create') do |f| %>
        <%= render partial: "stripe_checkout_button" %>
        <%= hidden_field_tag(:course_id, @course.id) %>

        <%= f.submit "Buy this course", class: "bg-blue hover:bg-blue-dark text-white font-semibold py-3 px-4 border-2 rounded-sm border-blue-dark shadow outline-none" %>
      <% end %>
  <% end %>
  </section>
<% else %>
  <section class="flex h-64 hero-banner p-4">
    <section class="flex items-center mx-auto">
      <h2 class="uppercase">
        <%= @course.title %>
      </h2>
    </section>
  </section>

  <section class="pt-4 px-4">
    <section class="w-full">
      <section class="rounded overflow-hidden shadow">
        <section style="padding: 56.25% 0 0 0; position: relative;">
          <iframe src="https://player.vimeo.com/video/<%= @course.trailer %>" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%;" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe>
        </section>
      </section>
    </section>

    <section class="flex flex-wrap -mx-4">
      <section class="w-full lg:w-3/4 p-4">
        <section class="bg-grey-lightest shadow text-grey-darker p-4">
          <h2 class="font-normal mb-4">Course description</h2>
          <p class="font-normal whitespace-pre-wrap"><%= @course.description %></p>
        </section>
      </section>
      <section class="w-full lg:w-1/4 p-4">
        <section class="bg-grey-lightest shadow text-grey-darker p-4 mb-4">
          <h3 class="font-normal mb-4">Course Price</h3>
          <p class="font-bold text-3xl text-green">£<%= @course.price %></p>
        </section>

        <%= link_to "Sign up to purchase", new_user_registration_path, class: "bg-blue hover:bg-blue-dark text-white font-semibold py-3 px-4 border-2 rounded-sm border-blue-dark shadow outline-none no-underline" %>

        <section class="bg-grey-lightest shadow text-grey-darker py-4 px-4 mt-4">
          <h3 class="font-normal mb-4">Course Modules</h3>
            <% @course_modules.each do |course_module| %>
              <section class="py-2 border-b-2 border-light modules">
                <%= course_module.title %>
              </section>
          <% end %>
        </section>
      </section>
    </section>
  </section>
<% end %>

Посмотрите, как, если у меня есть, если модуль завершен, должна быть показана зеленая галочка, и в идеале запись должна идти в таблицу course_modules_users, потому что заполненное поле должно пометить модуль курса как true в заполненное поле.

Часть кода в моделях взята из предыдущего решения, помечающего модуль курса для всех пользователей.

Так что, если я не ошибаюсь, мне просто нужно перенести текущую функциональность в новые методы complete? и получить данные в новых таблицах базы данных

Тем не менее, для меня новость в том, что любая помощь в знании того, как это сделать, будет очень признательна.

1 Ответ

0 голосов
/ 15 сентября 2018

вы на правильном пути

как только пользователь покупает курс или запускает курс, вы создаете все необходимые записи в course_users и course_modules_users с complete, установленным на false

добавьте courses_user_id в course_modules_users таблицу и вы можете удалить user_id

User класс

class User < ApplicationRecord
  has_many :courses_users
  has_many :course_modules_users, through: :courses_users
end

CoursesUser класс

class CoursesUser < ApplicationRecord
  belongs_to :course
  belongs_to :user

  has_many :course_modules_users

  def completed!
    self.update_attributes(complete: true)
  end
end

CourseModulesUser класс

class CourseModulesUser < ApplicationRecord
  belongs_to :course_module
  belongs_to :courses_user

  after_update :update_courses_user, if: :completed?

  def siblings
    self.class.where(courses_user_id: self.courses_user_id)
  end

  def completed!
    self.update_attributes(complete: true)
  end

  def completed?
    siblings.all?(&:complete?)
  end

  def update_courses_user
    self.courses_user.completed!
  end
end

в complete_course_module_path действии контроллера вы можете извлечь course_modules_users записей и пометить его как завершенное

cmu = current_user.course_modules_users.find_by(course_module_id: params[:id])
      # params[:id] is course_modules.id
cmu.completed!

, чтобы отобразить модуль course_module как выполненныйв представлении вы можете запросить current_user.course_modules_users.find_by(course_module_id: params[:id]) и проверить complete столбец

Лучшим способом было бы использовать CoursesUser вместо CourseModule и извлекать записи оттуда что-то вроде current_user.courses_users.includes(course_modules_users: [course_module: :course_exercises]).find_by(course_id: 1)

затем вы можете перенести функциональность complete на отдельный контроллер CourseModulesUserController

...