Merge branches 'dev_aliyun' and 'dev_item_bank' of https://bdgit.educoder.net/Hjqreturn/educoder into dev_item_bank
	
		
	
				
					
				
			
						commit
						17150f863f
					
				| @ -1,14 +1,57 @@ | |||||||
| class LibrariesController < ApplicationController | class ItemBanksController < ApplicationController | ||||||
|   include PaginateHelper |   include PaginateHelper | ||||||
|  |   before_action :require_login | ||||||
|  |   before_action :find_item, except: [:index, :create] | ||||||
|  |   before_action :edit_auth, only: [:update, :destroy, :set_public] | ||||||
| 
 | 
 | ||||||
|   def index |   def index | ||||||
|     default_sort('updated_at', 'desc') |     items = ItemBankQuery.call(params) | ||||||
| 
 |     @items_count = items.size | ||||||
|     @items = ItemBankQuery.call(params) |     @items = paginate items.includes(:item_analysis, :user) | ||||||
|     @items = paginate courses.includes(:school, :students, :attachments, :homework_commons, teacher: :user_extension) |  | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|   def create |   def create | ||||||
|  |     item = ItemBank.new(user: current_user) | ||||||
|  |     ItemBanks::SaveItemService.call(item, form_params) | ||||||
|  |     render_ok | ||||||
|  |   rescue ApplicationService::Error => ex | ||||||
|  |     render_error(ex.message) | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|  |   def edit | ||||||
|  | 
 | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|  |   def update | ||||||
|  |     ItemBanks::SaveItemService.call(@item, form_params) | ||||||
|  |     render_ok | ||||||
|  |   rescue ApplicationService::Error => ex | ||||||
|  |     render_error(ex.message) | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|  |   def destroy | ||||||
|  |     @item.destroy! | ||||||
|  |     render_ok | ||||||
|  |   end | ||||||
| 
 | 
 | ||||||
|  |   def set_public | ||||||
|  |     tip_exception(-1, "该试题已公开") if @item.public? | ||||||
|  |     @item.update_attributes!(public: 1) | ||||||
|  |     render_ok | ||||||
|   end |   end | ||||||
|  | 
 | ||||||
|  |   private | ||||||
|  | 
 | ||||||
|  |   def find_item | ||||||
|  |     @item = ItemBank.find_by!(id: params[:id]) | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|  |   def edit_auth | ||||||
|  |     current_user.admin_or_business? || @item.user == current_user | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|  |   def form_params | ||||||
|  |     params.permit(:repertoire_id, :sub_repertoire_id, :item_type, :difficulty, :name, :analysis, tag_repertoire_id: [], choices: %i[choice_text is_answer]) | ||||||
|  |   end | ||||||
|  | 
 | ||||||
| end | end | ||||||
| @ -0,0 +1,47 @@ | |||||||
|  | class ItemBasketsController < ApplicationController | ||||||
|  |   before_action :require_login | ||||||
|  | 
 | ||||||
|  |   def index | ||||||
|  |     @item_baskets = current_user.item_baskets | ||||||
|  |     @single_questions = @item_baskets.where(item_type: "SINGLE") | ||||||
|  |     @multiple_questions = @item_baskets.where(item_type: "MULTIPLE") | ||||||
|  |     @judgement_questions = @item_baskets.where(item_type: "JUDGMENT") | ||||||
|  |     @program_questions = @item_baskets.where(item_type: "PROGRAM") | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|  |   def basket_list | ||||||
|  |     @single_questions_count = current_user.item_baskets.where(item_type: "SINGLE").count | ||||||
|  |     @multiple_questions_count = current_user.item_baskets.where(item_type: "MULTIPLE").count | ||||||
|  |     @judgement_questions_count = current_user.item_baskets.where(item_type: "JUDGMENT").count | ||||||
|  |     @completion_questions_count = current_user.item_baskets.where(item_type: "COMPLETION").count | ||||||
|  |     @subjective_questions_count = current_user.item_baskets.where(item_type: "SUBJECTIVE").count | ||||||
|  |     @practical_questions_count = current_user.item_baskets.where(item_type: "PRACTICAL").count | ||||||
|  |     @program_questions_count = current_user.item_baskets.where(item_type: "PROGRAM").count | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|  |   def create | ||||||
|  |     ItemBaskets::SaveItemBasketService.call(current_user, create_params) | ||||||
|  |     render_ok | ||||||
|  |   rescue ApplicationService::Error => ex | ||||||
|  |     render_error(ex.message) | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|  |   def destroy | ||||||
|  |     item = current_user.item_baskets.find_by!(item_bank_id: params[:id]) | ||||||
|  |     ActiveRecord::Base.transaction do | ||||||
|  |       current_user.item_baskets.where("item_type = #{item.item_type} and position > #{item.position}").update_all("position = position -1") | ||||||
|  |       item.destroy! | ||||||
|  |     end | ||||||
|  |     render_ok | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|  |   def delete_item_type | ||||||
|  |     # tip_exception() unless | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|  |   private | ||||||
|  | 
 | ||||||
|  |   def create_params | ||||||
|  |     params.permit(item_ids: []) | ||||||
|  |   end | ||||||
|  | end | ||||||
| @ -0,0 +1,33 @@ | |||||||
|  | class ItemBanks::SaveItemForm | ||||||
|  |   include ActiveModel::Model | ||||||
|  | 
 | ||||||
|  |   attr_accessor :repertoire_id, :sub_repertoire_id, :item_type, :difficulty, :name, :analysis, :tag_repertoire_id, :choices | ||||||
|  | 
 | ||||||
|  |   validates :repertoire_id, presence: true | ||||||
|  |   validates :sub_repertoire_id, presence: true | ||||||
|  |   validates :item_type, presence: true, inclusion: {in: %W(SINGLE MULTIPLE JUDGMENT COMPLETION SUBJECTIVE PRACTICAL PROGRAM)} | ||||||
|  |   validates :difficulty, presence: true, inclusion: {in: 1..3}, numericality: { only_integer: true } | ||||||
|  |   validates :name, presence: true, length: { maximum: 1000 } | ||||||
|  |   validates :analysis, length: { maximum: 1000 } | ||||||
|  | 
 | ||||||
|  |   def validate! | ||||||
|  |     super | ||||||
|  |     return unless errors.blank? | ||||||
|  |     choices.each { |item| SubForm.new(item).validate! } if  %W(SINGLE MULTIPLE JUDGMENT).include?(item_type) | ||||||
|  |     return unless errors.blank? | ||||||
|  |     if [0, 2].include?(item_type) && choices.pluck(:is_answer).select{|item| item == 1}.length > 1 | ||||||
|  |       raise("正确答案只能有一个") | ||||||
|  |     elsif item_type == 1 && choices.pluck(:is_answer).select{|item| item == 1}.length <= 1 | ||||||
|  |       raise("多选题至少有两个正确答案") | ||||||
|  |     end | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|  |   class SubForm | ||||||
|  |     include ActiveModel::Model | ||||||
|  | 
 | ||||||
|  |     attr_accessor :choice_text, :is_answer | ||||||
|  | 
 | ||||||
|  |     validates :choice_text, presence: true, length: { maximum: 100 } | ||||||
|  |     validates :is_answer, presence: true, inclusion: {in: 0..1}, numericality: { only_integer: true } | ||||||
|  |   end | ||||||
|  | end | ||||||
| @ -1,11 +1,18 @@ | |||||||
| class ItemBank < ApplicationRecord | class ItemBank < ApplicationRecord | ||||||
|   # difficulty:  1 简单  2 适中  3 困难 |   # difficulty:  1 简单  2 适中  3 困难 | ||||||
|   # item_type:  0 单选  1 多选  2 判断  3 填空  4 简答  5 实训 6 编程 |  | ||||||
|   enum item_type: { SINGLE: 0, MULTIPLE: 1, JUDGMENT: 2, COMPLETION: 3, SUBJECTIVE: 4, PRACTICAL: 5, PROGRAM: 6 } |   enum item_type: { SINGLE: 0, MULTIPLE: 1, JUDGMENT: 2, COMPLETION: 3, SUBJECTIVE: 4, PRACTICAL: 5, PROGRAM: 6 } | ||||||
|  |   # item_type:  0 单选  1 多选  2 判断  3 填空  4 简答  5 实训 6 编程 | ||||||
| 
 | 
 | ||||||
|   belongs_to :user |   belongs_to :user | ||||||
|  |   belongs_to :sub_repertoire | ||||||
| 
 | 
 | ||||||
|   has_one :item_analysis, dependent: :destroy |   has_one :item_analysis, dependent: :destroy | ||||||
|   has_many :item_choices, dependent: :destroy |   has_many :item_choices, dependent: :destroy | ||||||
|   has_many :item_baskets, dependent: :destroy |   has_many :item_baskets, dependent: :destroy | ||||||
|  |   has_many :item_bank_tag_repertoires, dependent: :destroy | ||||||
|  |   has_many :tag_repertoires, through: :item_bank_tag_repertoires | ||||||
|  | 
 | ||||||
|  |   def analysis | ||||||
|  |     item_analysis&.analysis | ||||||
|  |   end | ||||||
| end | end | ||||||
|  | |||||||
| @ -0,0 +1,4 @@ | |||||||
|  | class ItemBankTagRepertoire < ApplicationRecord | ||||||
|  |   belongs_to :item_bank | ||||||
|  |   belongs_to :tag_repertoire | ||||||
|  | end | ||||||
| @ -1,4 +1,14 @@ | |||||||
| class ItemBasket < ApplicationRecord | class ItemBasket < ApplicationRecord | ||||||
|  |   enum item_type: { SINGLE: 0, MULTIPLE: 1, JUDGMENT: 2, COMPLETION: 3, SUBJECTIVE: 4, PRACTICAL: 5, PROGRAM: 6 } | ||||||
|  | 
 | ||||||
|   belongs_to :item_bank |   belongs_to :item_bank | ||||||
|   belongs_to :user |   belongs_to :user | ||||||
|  | 
 | ||||||
|  |   def all_score | ||||||
|  |     User.current.item_baskets.map(&:score).sum | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|  |   def question_count | ||||||
|  |     User.current.item_baskets.size | ||||||
|  |   end | ||||||
| end | end | ||||||
|  | |||||||
| @ -0,0 +1,33 @@ | |||||||
|  | class ItemBankQuery < ApplicationQuery | ||||||
|  |   include CustomSortable | ||||||
|  |   attr_reader :params | ||||||
|  | 
 | ||||||
|  |   sort_columns :updated_at, default_by: :updated_at, default_direction: :desc, default_table: 'item_banks' | ||||||
|  | 
 | ||||||
|  |   def initialize(params) | ||||||
|  |     @params = params | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|  |   def call | ||||||
|  |     if params[:public].to_i == 1 | ||||||
|  |       items = ItemBank.where(public: 1) | ||||||
|  |     elsif params[:public].to_i == 0 | ||||||
|  |       items = ItemBank.where(user_id: User.current.id) | ||||||
|  |     end | ||||||
|  | 
 | ||||||
|  |     if params[:tag_repertoire_id].present? | ||||||
|  |       items = items.joins(:item_bank_tag_repertoires).where(item_bank_tag_repertoires: {tag_repertoire_id: params[:tag_repertoire_id]}) | ||||||
|  |     elsif params[:sub_repertoire_id].present? | ||||||
|  |       items = items.where(sub_repertoire_id: params[:sub_repertoire_id]) | ||||||
|  |     elsif params[:repertoire_id].present? | ||||||
|  |       items = items.joins(:sub_repertoire).where(sub_repertoires: {repertoire_id: params[:repertoire_id]}) | ||||||
|  |     end | ||||||
|  | 
 | ||||||
|  |     items = items.where(item_type: params[:item_type].to_i) if params[:item_type].present? | ||||||
|  |     items = items.where(difficulty: params[:difficulty].to_i) if params[:difficulty].present? | ||||||
|  | 
 | ||||||
|  |     items = items.where("name like ?", "%#{params[:keyword].strip}%") if params[:keyword].present? | ||||||
|  | 
 | ||||||
|  |     custom_sort(items, params[:sort_by], params[:sort_direction]) | ||||||
|  |   end | ||||||
|  | end | ||||||
| @ -0,0 +1,58 @@ | |||||||
|  | class ItemBanks::SaveItemService < ApplicationService | ||||||
|  |   attr_reader :item, :params | ||||||
|  | 
 | ||||||
|  |   def initialize(item, params) | ||||||
|  |     @item = item | ||||||
|  |     @params = params | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|  |   def call | ||||||
|  |     new_record = item.new_record? | ||||||
|  |     raise("不能更改题型") if !new_record && item.item_type != params[:item_type] | ||||||
|  |     ItemBanks::SaveItemForm.new(params).validate! | ||||||
|  | 
 | ||||||
|  |     ActiveRecord::Base.transaction do | ||||||
|  |       item.item_type = params[:item_type] if new_record | ||||||
|  |       item.difficulty = params[:difficulty] | ||||||
|  |       item.sub_repertoire_id = params[:sub_repertoire_id] | ||||||
|  |       item.name = params[:name].strip | ||||||
|  |       item.save! | ||||||
|  | 
 | ||||||
|  |       analysis = item.item_analysis || ItemAnalysis.new(item_bank_id: item.id) | ||||||
|  |       analysis.analysis = params[:analysis].blank? ? nil : params[:analysis].strip | ||||||
|  |       analysis.save | ||||||
|  | 
 | ||||||
|  |       # 知识点的创建 | ||||||
|  |       new_tag_repertoire_ids = params[:tag_repertoire_id] | ||||||
|  |       old_tag_repertoire_ids = item.item_bank_tag_repertoires.pluck(:tag_repertoire_id) | ||||||
|  |       delete_tag_repertoire_ids = old_tag_repertoire_ids - new_tag_repertoire_ids | ||||||
|  |       create_tag_repertoire_ids = new_tag_repertoire_ids - old_tag_repertoire_ids | ||||||
|  |       item.item_bank_tag_repertoires.where(tag_repertoire_id: delete_tag_repertoire_ids).destroy_all | ||||||
|  |       create_tag_repertoire_ids.each do |tag_id| | ||||||
|  |         item.item_bank_tag_repertoires << ItemBankTagRepertoire.new(tag_repertoire_id: tag_id) | ||||||
|  |       end | ||||||
|  | 
 | ||||||
|  |       # 选项的创建 | ||||||
|  |       if %W(SINGLE MULTIPLE JUDGMENT).include?(item.item_type) | ||||||
|  |         old_choices = item.item_choices | ||||||
|  |         new_choices = params[:choices] | ||||||
|  | 
 | ||||||
|  |         new_choices.each_with_index do |choice, index| | ||||||
|  |           choice_item = old_choices[index] || ItemChoice.new(item_bank_id: item.id) | ||||||
|  |           choice_item.choice_text = choice[:choice_text] | ||||||
|  |           choice_item.is_answer = choice[:is_answer] | ||||||
|  |           choice_item.save! | ||||||
|  |         end | ||||||
|  | 
 | ||||||
|  |         if old_choices.length > new_choices.length | ||||||
|  |           old_choices[new_choices.length..(old_choices.length-1)].each do |old_choice| | ||||||
|  |             old_choice.destroy | ||||||
|  |           end | ||||||
|  |         end | ||||||
|  | 
 | ||||||
|  |       end | ||||||
|  |     end | ||||||
|  | 
 | ||||||
|  |     item | ||||||
|  |   end | ||||||
|  | end | ||||||
| @ -0,0 +1,47 @@ | |||||||
|  | class ItemBaskets::SaveItemBasketService < ApplicationService | ||||||
|  |   attr_reader :user, :params | ||||||
|  | 
 | ||||||
|  |   def initialize(user, params) | ||||||
|  |     @user = user | ||||||
|  |     @params = params | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|  |   def call | ||||||
|  |     raise("请选择试题") if params[:item_ids].blank? | ||||||
|  | 
 | ||||||
|  |     # 只能选用公共题库或是自己的题库 | ||||||
|  |     items = ItemBank.where(public: 1).or(ItemBank.where(user_id: user.id)) | ||||||
|  | 
 | ||||||
|  |     # 已选到过试题篮的不重复选用 | ||||||
|  |     item_ids = params[:item_ids] - user.item_baskets.pluck(:item_bank_id) | ||||||
|  |     items.where(id: item_ids).each do |item| | ||||||
|  |       new_item = ItemBasket.new(user_id: user.id, item_bank_id: item.id, item_type: item.item_type) | ||||||
|  |       new_item.score = item_score item.item_type | ||||||
|  |       new_item.position = item_position item.item_type | ||||||
|  |       new_item.save! | ||||||
|  |     end | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|  |   private | ||||||
|  | 
 | ||||||
|  |   def item_score item_type | ||||||
|  |     if user.item_baskets.where(item_type: item_type).last.present? | ||||||
|  |       score = user.item_baskets.where(item_type: item_type).last.score | ||||||
|  |     else | ||||||
|  |       score = | ||||||
|  |         case item_type | ||||||
|  |         when 0, 1, 2 | ||||||
|  |           5 | ||||||
|  |         when 6 | ||||||
|  |           10 | ||||||
|  |         else | ||||||
|  |           5 | ||||||
|  |         end | ||||||
|  |     end | ||||||
|  |     score | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|  |   def item_position item_type | ||||||
|  |     user.item_baskets.where(item_type: item_type).last&.position.to_i + 1 | ||||||
|  |   end | ||||||
|  | end | ||||||
| @ -0,0 +1,6 @@ | |||||||
|  | json.(item, :id, :name, :item_type, :difficulty, :public, :quotes) | ||||||
|  | json.analysis item.analysis | ||||||
|  | json.choices item.item_choices do |choice| | ||||||
|  |   json.choice_text choice.choice_text | ||||||
|  |   json.is_answer choice.is_answer | ||||||
|  | end | ||||||
| @ -0,0 +1,15 @@ | |||||||
|  | json.repertoire do | ||||||
|  |   json.(@item.sub_repertoire&.repertoire, :id, :name) | ||||||
|  | end | ||||||
|  | json.sub_repertoire do | ||||||
|  |   json.(@item.sub_repertoire, :id, :name) | ||||||
|  | end | ||||||
|  | json.tag_repertoires @item.tag_repertoires do |tag| | ||||||
|  |   json.(tag, :id, :name) | ||||||
|  | end | ||||||
|  | json.(@item, :id, :name, :item_type, :difficulty) | ||||||
|  | json.analysis @item.analysis | ||||||
|  | json.choices @item.item_choices do |choice| | ||||||
|  |   json.choice_text choice.choice_text | ||||||
|  |   json.is_answer choice.is_answer | ||||||
|  | end | ||||||
| @ -0,0 +1,9 @@ | |||||||
|  | json.items @items.each do |item| | ||||||
|  |   json.partial! "item_banks/item", locals: {item: item} | ||||||
|  |   json.update_time item.updated_at&.strftime("%Y-%m-%d %H:%M") | ||||||
|  |   json.author do | ||||||
|  |     json.login item.user&.login | ||||||
|  |     json.name item.user&.full_name | ||||||
|  |   end | ||||||
|  | end | ||||||
|  | json.items_count @items_count | ||||||
| @ -0,0 +1,7 @@ | |||||||
|  | json.single_questions_count @single_questions_count | ||||||
|  | json.multiple_questions_count @multiple_questions_count | ||||||
|  | json.judgement_questions_count @judgement_questions_count | ||||||
|  | json.completion_questions_count @completion_questions_count | ||||||
|  | json.subjective_questions_count @subjective_questions_count | ||||||
|  | json.practical_questions_count @practical_questions_count | ||||||
|  | json.program_questions_count @program_questions_count | ||||||
| @ -0,0 +1,38 @@ | |||||||
|  | json.single_questions do | ||||||
|  |   json.questions @single_questions.each do |question| | ||||||
|  |     json.(question, :id, :position, :score, :item_type) | ||||||
|  |     json.partial! "item_banks/item", locals: {item: question.item_bank} | ||||||
|  |   end | ||||||
|  |   json.questions_score @single_questions.map(&:score).sum | ||||||
|  |   json.questions_count @single_questions.size | ||||||
|  | end | ||||||
|  | 
 | ||||||
|  | json.multiple_questions do | ||||||
|  |   json.questions @multiple_questions.each do |question| | ||||||
|  |     json.(question, :id, :position, :score, :item_type) | ||||||
|  |     json.partial! "item_banks/item", locals: {item: question.item_bank} | ||||||
|  |   end | ||||||
|  |   json.questions_score @multiple_questions.map(&:score).sum | ||||||
|  |   json.questions_count @multiple_questions.size | ||||||
|  | end | ||||||
|  | 
 | ||||||
|  | json.judgement_questions do | ||||||
|  |   json.questions @judgement_questions.each do |question| | ||||||
|  |     json.(question, :id, :position, :score, :item_type) | ||||||
|  |     json.partial! "item_banks/item", locals: {item: question.item_bank} | ||||||
|  |   end | ||||||
|  |   json.questions_score @judgement_questions.map(&:score).sum | ||||||
|  |   json.questions_count @judgement_questions.size | ||||||
|  | end | ||||||
|  | 
 | ||||||
|  | json.program_questions do | ||||||
|  |   json.questions @program_questions.each do |question| | ||||||
|  |     json.(question, :id, :position, :score, :item_type) | ||||||
|  |     json.partial! "item_banks/item", locals: {item: question.item_bank} | ||||||
|  |   end | ||||||
|  |   json.questions_score @program_questions.map(&:score).sum | ||||||
|  |   json.questions_count @program_questions.size | ||||||
|  | end | ||||||
|  | 
 | ||||||
|  | json.all_score @item_baskets.map(&:score).sum | ||||||
|  | json.all_questions_count @item_baskets.size | ||||||
| @ -0,0 +1,7 @@ | |||||||
|  | class MigrateItemBankColumn < ActiveRecord::Migration[5.2] | ||||||
|  |   def change | ||||||
|  |     remove_column :item_banks, :curriculum_id | ||||||
|  |     remove_column :item_banks, :curriculum_direction_id | ||||||
|  |     add_column :item_banks, :sub_repertoire_id, :integer, index: true | ||||||
|  |   end | ||||||
|  | end | ||||||
| @ -0,0 +1,10 @@ | |||||||
|  | class CreateItemBankTagRepertoires < ActiveRecord::Migration[5.2] | ||||||
|  |   def change | ||||||
|  |     create_table :item_bank_tag_repertoires do |t| | ||||||
|  |       t.references :item_bank, index: true | ||||||
|  |       t.references :tag_repertoire, index: true | ||||||
|  | 
 | ||||||
|  |       t.timestamps | ||||||
|  |     end | ||||||
|  |   end | ||||||
|  | end | ||||||
| @ -0,0 +1,7 @@ | |||||||
|  | class ChangeItemBankPublicDefault < ActiveRecord::Migration[5.2] | ||||||
|  |   def change | ||||||
|  |     change_column_default :item_banks, :public, 0 | ||||||
|  |     change_column_default :item_banks, :quotes, 0 | ||||||
|  |     change_column_default :item_banks, :difficulty, 1 | ||||||
|  |   end | ||||||
|  | end | ||||||
| @ -0,0 +1,7 @@ | |||||||
|  | class AddPositionScoreToBasket < ActiveRecord::Migration[5.2] | ||||||
|  |   def change | ||||||
|  |     add_column :item_baskets, :position, :integer, default: 0 | ||||||
|  |     add_column :item_baskets, :score, :float, default: 0 | ||||||
|  |     add_column :item_baskets, :item_type, :integer, default: 0 | ||||||
|  |   end | ||||||
|  | end | ||||||
| @ -0,0 +1,5 @@ | |||||||
|  | require 'rails_helper' | ||||||
|  | 
 | ||||||
|  | RSpec.describe ItemBankTagRepertoire, type: :model do | ||||||
|  |   pending "add some examples to (or delete) #{__FILE__}" | ||||||
|  | end | ||||||
					Loading…
					
					
				
		Reference in new issue