diff --git a/app/controllers/dashboard/examples_controller.rb b/app/controllers/dashboard/examples_controller.rb
new file mode 100644
index 0000000..c2b96dc
--- /dev/null
+++ b/app/controllers/dashboard/examples_controller.rb
@@ -0,0 +1,60 @@
+module Dashboard
+ class ExamplesController < ApplicationController
+ before_action :set_example, only: %i[ show edit update destroy ]
+
+ # GET /examples
+ def index
+ @examples = Example.all
+ end
+
+ # GET /examples/1
+ def show
+ end
+
+ # GET /examples/new
+ def new
+ @example = Example.new
+ end
+
+ # GET /examples/1/edit
+ def edit
+ end
+
+ # POST /examples
+ def create
+ @example = Example.new(example_params)
+
+ if @example.save
+ redirect_to @example, notice: "Example was successfully created."
+ else
+ render :new, status: :unprocessable_entity
+ end
+ end
+
+ # PATCH/PUT /examples/1
+ def update
+ if @example.update(example_params)
+ redirect_to @example, notice: "Example was successfully updated.", status: :see_other
+ else
+ render :edit, status: :unprocessable_entity
+ end
+ end
+
+ # DELETE /examples/1
+ def destroy
+ @example.destroy!
+ redirect_to examples_url, notice: "Example was successfully destroyed.", status: :see_other
+ end
+
+ private
+ # Use callbacks to share common setup or constraints between actions.
+ def set_example
+ @example = Example.find(params[:id])
+ end
+
+ # Only allow a list of trusted parameters through.
+ def example_params
+ params.require(:example).permit(:text, :body)
+ end
+ end
+end
diff --git a/app/helpers/dashboard/examples_helper.rb b/app/helpers/dashboard/examples_helper.rb
new file mode 100644
index 0000000..d7c4dbd
--- /dev/null
+++ b/app/helpers/dashboard/examples_helper.rb
@@ -0,0 +1,4 @@
+module Dashboard
+ module ExamplesHelper
+ end
+end
diff --git a/app/models/dashboard/example.rb b/app/models/dashboard/example.rb
new file mode 100644
index 0000000..9f42183
--- /dev/null
+++ b/app/models/dashboard/example.rb
@@ -0,0 +1,4 @@
+module Dashboard
+ class Example < ApplicationRecord
+ end
+end
diff --git a/app/views/dashboard/examples/_example.html.erb b/app/views/dashboard/examples/_example.html.erb
new file mode 100644
index 0000000..17eac30
--- /dev/null
+++ b/app/views/dashboard/examples/_example.html.erb
@@ -0,0 +1,12 @@
+
+
+ Text:
+ <%= example.text %>
+
+
+
+ Body:
+ <%= example.body %>
+
+
+
diff --git a/app/views/dashboard/examples/_form.html.erb b/app/views/dashboard/examples/_form.html.erb
new file mode 100644
index 0000000..7a3ee22
--- /dev/null
+++ b/app/views/dashboard/examples/_form.html.erb
@@ -0,0 +1,27 @@
+<%= form_with(model: example) do |form| %>
+ <% if example.errors.any? %>
+
+
<%= pluralize(example.errors.count, "error") %> prohibited this example from being saved:
+
+
+ <% example.errors.each do |error| %>
+ - <%= error.full_message %>
+ <% end %>
+
+
+ <% end %>
+
+
+ <%= form.label :text, style: "display: block" %>
+ <%= form.text_field :text %>
+
+
+
+ <%= form.label :body, style: "display: block" %>
+ <%= form.text_area :body %>
+
+
+
+ <%= form.submit %>
+
+<% end %>
diff --git a/app/views/dashboard/examples/edit.html.erb b/app/views/dashboard/examples/edit.html.erb
new file mode 100644
index 0000000..92b1731
--- /dev/null
+++ b/app/views/dashboard/examples/edit.html.erb
@@ -0,0 +1,10 @@
+Editing example
+
+<%= render "form", example: @example %>
+
+
+
+
+ <%= link_to "Show this example", @example %> |
+ <%= link_to "Back to examples", examples_path %>
+
diff --git a/app/views/dashboard/examples/index.html.erb b/app/views/dashboard/examples/index.html.erb
new file mode 100644
index 0000000..6eed656
--- /dev/null
+++ b/app/views/dashboard/examples/index.html.erb
@@ -0,0 +1,14 @@
+<%= notice %>
+
+Examples
+
+
+ <% @examples.each do |example| %>
+ <%= render example %>
+
+ <%= link_to "Show this example", example %>
+
+ <% end %>
+
+
+<%= link_to "New example", new_example_path %>
diff --git a/app/views/dashboard/examples/new.html.erb b/app/views/dashboard/examples/new.html.erb
new file mode 100644
index 0000000..3986849
--- /dev/null
+++ b/app/views/dashboard/examples/new.html.erb
@@ -0,0 +1,9 @@
+New example
+
+<%= render "form", example: @example %>
+
+
+
+
+ <%= link_to "Back to examples", examples_path %>
+
diff --git a/app/views/dashboard/examples/show.html.erb b/app/views/dashboard/examples/show.html.erb
new file mode 100644
index 0000000..e58d608
--- /dev/null
+++ b/app/views/dashboard/examples/show.html.erb
@@ -0,0 +1,10 @@
+<%= notice %>
+
+<%= render @example %>
+
+
+ <%= link_to "Edit this example", edit_example_path(@example) %> |
+ <%= link_to "Back to examples", examples_path %>
+
+ <%= button_to "Destroy this example", @example, method: :delete %>
+
diff --git a/config/routes.rb b/config/routes.rb
index a63ec31..3fb7434 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -1,2 +1,3 @@
Dashboard::Engine.routes.draw do
+ resources :examples
end
diff --git a/db/migrate/20231223040511_create_dashboard_examples.rb b/db/migrate/20231223040511_create_dashboard_examples.rb
new file mode 100644
index 0000000..0108ae7
--- /dev/null
+++ b/db/migrate/20231223040511_create_dashboard_examples.rb
@@ -0,0 +1,10 @@
+class CreateDashboardExamples < ActiveRecord::Migration[7.1]
+ def change
+ create_table :dashboard_examples do |t|
+ t.string :text
+ t.text :body
+
+ t.timestamps
+ end
+ end
+end
diff --git a/lib/dashboard/engine.rb b/lib/dashboard/engine.rb
index 88d7a16..d676b9d 100644
--- a/lib/dashboard/engine.rb
+++ b/lib/dashboard/engine.rb
@@ -1,5 +1,11 @@
module Dashboard
class Engine < ::Rails::Engine
isolate_namespace Dashboard
+
+ config.generators do |g|
+ g.test_framework :rspec
+ g.fixture_replacement :factory_bot
+ g.factory_bot dir: "spec/factories"
+ end
end
end
diff --git a/spec/dummy/db/schema.rb b/spec/dummy/db/schema.rb
new file mode 100644
index 0000000..1b07f5b
--- /dev/null
+++ b/spec/dummy/db/schema.rb
@@ -0,0 +1,24 @@
+# This file is auto-generated from the current state of the database. Instead
+# of editing this file, please use the migrations feature of Active Record to
+# incrementally modify your database, and then regenerate this schema definition.
+#
+# This file is the source Rails uses to define your schema when running `bin/rails
+# db:schema:load`. When creating a new database, `bin/rails db:schema:load` tends to
+# be faster and is potentially less error prone than running all of your
+# migrations from scratch. Old migrations may fail to apply correctly if those
+# migrations use external dependencies or application code.
+#
+# It's strongly recommended that you check this file into your version control system.
+
+ActiveRecord::Schema[7.1].define(version: 2023_12_23_040511) do
+ # These are extensions that must be enabled in order to support this database
+ enable_extension "plpgsql"
+
+ create_table "dashboard_examples", force: :cascade do |t|
+ t.string "text"
+ t.text "body"
+ t.datetime "created_at", null: false
+ t.datetime "updated_at", null: false
+ end
+
+end
diff --git a/spec/factories/dashboard/examples.rb b/spec/factories/dashboard/examples.rb
new file mode 100644
index 0000000..09396d6
--- /dev/null
+++ b/spec/factories/dashboard/examples.rb
@@ -0,0 +1,6 @@
+FactoryBot.define do
+ factory :example, class: "Dashboard::Example" do
+ text { "MyString" }
+ body { "MyText" }
+ end
+end
diff --git a/spec/helpers/dashboard/examples_helper_spec.rb b/spec/helpers/dashboard/examples_helper_spec.rb
new file mode 100644
index 0000000..0e6c57a
--- /dev/null
+++ b/spec/helpers/dashboard/examples_helper_spec.rb
@@ -0,0 +1,17 @@
+require 'rails_helper'
+
+# Specs in this file have access to a helper object that includes
+# the ExamplesHelper. For example:
+#
+# describe ExamplesHelper do
+# describe "string concat" do
+# it "concats two strings with spaces" do
+# expect(helper.concat_strings("this","that")).to eq("this that")
+# end
+# end
+# end
+module Dashboard
+ RSpec.describe ExamplesHelper, type: :helper do
+ pending "add some examples to (or delete) #{__FILE__}"
+ end
+end
diff --git a/spec/models/dashboard/example_spec.rb b/spec/models/dashboard/example_spec.rb
new file mode 100644
index 0000000..ec767e1
--- /dev/null
+++ b/spec/models/dashboard/example_spec.rb
@@ -0,0 +1,10 @@
+require "rails_helper"
+
+module Dashboard
+ RSpec.describe Example, type: :model do
+ it "creates an example to test rspec and factorybot" do
+ create(:example)
+ expect(Example.count).to eq 1
+ end
+ end
+end
diff --git a/spec/rails_helper.rb b/spec/rails_helper.rb
index a15455f..62024d6 100644
--- a/spec/rails_helper.rb
+++ b/spec/rails_helper.rb
@@ -1,10 +1,11 @@
# This file is copied to spec/ when you run 'rails generate rspec:install'
-require 'spec_helper'
-ENV['RAILS_ENV'] ||= 'test'
-require_relative '../config/environment'
+require "spec_helper"
+ENV["RAILS_ENV"] ||= "test"
+require_relative "../spec/dummy/config/environment"
# Prevent database truncation if the environment is production
abort("The Rails environment is running in production mode!") if Rails.env.production?
-require 'rspec/rails'
+require "rspec/rails"
+
# Add additional requires below this line. Rails is not loaded until this point!
# Requires supporting ruby files with custom matchers and macros, etc, in
@@ -29,12 +30,19 @@ begin
rescue ActiveRecord::PendingMigrationError => e
abort e.to_s.strip
end
+
+require "factory_bot_rails"
+
+FactoryBot.definition_file_paths << File.join(File.dirname(__FILE__), "factories")
+FactoryBot.factories.clear
+FactoryBot.find_definitions
+
RSpec.configure do |config|
# Remove this line if you're not using ActiveRecord or ActiveRecord fixtures
config.fixture_paths = [
- Rails.root.join('spec/fixtures')
+ Rails.root.join("spec/fixtures")
]
-
+ config.include FactoryBot::Syntax::Methods
# If you're not using ActiveRecord, or you'd prefer not to run each of your
# examples within a transaction, remove the following line or assign false
# instead of true.
@@ -62,4 +70,9 @@ RSpec.configure do |config|
config.filter_rails_from_backtrace!
# arbitrary gems may also be filtered via:
# config.filter_gems_from_backtrace("gem name")
+ config.before(:example, type: :view) do
+ view.class_eval do
+ include Dashboard::Engine.routes.url_helpers
+ end
+ end
end
diff --git a/spec/requests/dashboard/examples_spec.rb b/spec/requests/dashboard/examples_spec.rb
new file mode 100644
index 0000000..5deb02c
--- /dev/null
+++ b/spec/requests/dashboard/examples_spec.rb
@@ -0,0 +1,138 @@
+require 'rails_helper'
+
+# This spec was generated by rspec-rails when you ran the scaffold generator.
+# It demonstrates how one might use RSpec to test the controller code that
+# was generated by Rails when you ran the scaffold generator.
+#
+# It assumes that the implementation code is generated by the rails scaffold
+# generator. If you are using any extension libraries to generate different
+# controller code, this generated spec may or may not pass.
+#
+# It only uses APIs available in rails and/or rspec-rails. There are a number
+# of tools you can use to make these specs even more expressive, but we're
+# sticking to rails and rspec-rails APIs to keep things simple and stable.
+
+module Dashboard
+ RSpec.describe "/examples", type: :request do
+ include Engine.routes.url_helpers
+
+ # This should return the minimal set of attributes required to create a valid
+ # Example. As you add validations to Example, be sure to
+ # adjust the attributes here as well.
+ let(:valid_attributes) {
+ skip("Add a hash of attributes valid for your model")
+ }
+
+ let(:invalid_attributes) {
+ skip("Add a hash of attributes invalid for your model")
+ }
+
+ describe "GET /index" do
+ it "renders a successful response" do
+ Example.create! valid_attributes
+ get examples_url
+ expect(response).to be_successful
+ end
+ end
+
+ describe "GET /show" do
+ it "renders a successful response" do
+ example = Example.create! valid_attributes
+ get example_url(example)
+ expect(response).to be_successful
+ end
+ end
+
+ describe "GET /new" do
+ it "renders a successful response" do
+ get new_example_url
+ expect(response).to be_successful
+ end
+ end
+
+ describe "GET /edit" do
+ it "renders a successful response" do
+ example = Example.create! valid_attributes
+ get edit_example_url(example)
+ expect(response).to be_successful
+ end
+ end
+
+ describe "POST /create" do
+ context "with valid parameters" do
+ it "creates a new Example" do
+ expect {
+ post examples_url, params: { example: valid_attributes }
+ }.to change(Example, :count).by(1)
+ end
+
+ it "redirects to the created example" do
+ post examples_url, params: { example: valid_attributes }
+ expect(response).to redirect_to(example_url(Example.last))
+ end
+ end
+
+ context "with invalid parameters" do
+ it "does not create a new Example" do
+ expect {
+ post examples_url, params: { example: invalid_attributes }
+ }.to change(Example, :count).by(0)
+ end
+
+
+ it "renders a response with 422 status (i.e. to display the 'new' template)" do
+ post examples_url, params: { example: invalid_attributes }
+ expect(response).to have_http_status(:unprocessable_entity)
+ end
+
+ end
+ end
+
+ describe "PATCH /update" do
+ context "with valid parameters" do
+ let(:new_attributes) {
+ skip("Add a hash of attributes valid for your model")
+ }
+
+ it "updates the requested example" do
+ example = Example.create! valid_attributes
+ patch example_url(example), params: { example: new_attributes }
+ example.reload
+ skip("Add assertions for updated state")
+ end
+
+ it "redirects to the example" do
+ example = Example.create! valid_attributes
+ patch example_url(example), params: { example: new_attributes }
+ example.reload
+ expect(response).to redirect_to(example_url(example))
+ end
+ end
+
+ context "with invalid parameters" do
+
+ it "renders a response with 422 status (i.e. to display the 'edit' template)" do
+ example = Example.create! valid_attributes
+ patch example_url(example), params: { example: invalid_attributes }
+ expect(response).to have_http_status(:unprocessable_entity)
+ end
+
+ end
+ end
+
+ describe "DELETE /destroy" do
+ it "destroys the requested example" do
+ example = Example.create! valid_attributes
+ expect {
+ delete example_url(example)
+ }.to change(Example, :count).by(-1)
+ end
+
+ it "redirects to the examples list" do
+ example = Example.create! valid_attributes
+ delete example_url(example)
+ expect(response).to redirect_to(examples_url)
+ end
+ end
+ end
+end
diff --git a/spec/routing/dashboard/examples_routing_spec.rb b/spec/routing/dashboard/examples_routing_spec.rb
new file mode 100644
index 0000000..3007913
--- /dev/null
+++ b/spec/routing/dashboard/examples_routing_spec.rb
@@ -0,0 +1,39 @@
+require "rails_helper"
+
+module Dashboard
+ RSpec.describe ExamplesController, type: :routing do
+ describe "routing" do
+ it "routes to #index" do
+ expect(get: "dashboard/examples").to route_to("dashboard/examples#index")
+ end
+
+ it "routes to #new" do
+ expect(get: "dashboard/examples/new").to route_to("dashboard/examples#new")
+ end
+
+ it "routes to #show" do
+ expect(get: "dashboard/examples/1").to route_to("dashboard/examples#show", id: "1")
+ end
+
+ it "routes to #edit" do
+ expect(get: "/dashboard/examples/1/edit").to route_to("dashboard/examples#edit", id: "1")
+ end
+
+ it "routes to #create" do
+ expect(post: "/dashboard/examples").to route_to("dashboard/examples#create")
+ end
+
+ it "routes to #update via PUT" do
+ expect(put: "/dashboard/examples/1").to route_to("dashboard/examples#update", id: "1")
+ end
+
+ it "routes to #update via PATCH" do
+ expect(patch: "/dashboard/examples/1").to route_to("dashboard/examples#update", id: "1")
+ end
+
+ it "routes to #destroy" do
+ expect(delete: "/dashboard/examples/1").to route_to("dashboard/examples#destroy", id: "1")
+ end
+ end
+ end
+end
diff --git a/spec/views/dashboard/examples/edit.html.erb_spec.rb b/spec/views/dashboard/examples/edit.html.erb_spec.rb
new file mode 100644
index 0000000..5162d25
--- /dev/null
+++ b/spec/views/dashboard/examples/edit.html.erb_spec.rb
@@ -0,0 +1,26 @@
+require "rails_helper"
+
+module Dashboard
+ RSpec.xdescribe "dashboard/examples/edit", type: :view do
+ let(:example) do
+ Example.create!(
+ text: "MyString",
+ body: "MyText"
+ )
+ end
+
+ before(:each) do
+ assign(:example, example)
+ end
+
+ it "renders the edit example form" do
+ render
+
+ assert_select "form[action=?][method=?]", example_path(example), "post" do
+ assert_select "input[name=?]", "example[text]"
+
+ assert_select "textarea[name=?]", "example[body]"
+ end
+ end
+ end
+end
diff --git a/spec/views/dashboard/examples/index.html.erb_spec.rb b/spec/views/dashboard/examples/index.html.erb_spec.rb
new file mode 100644
index 0000000..649774b
--- /dev/null
+++ b/spec/views/dashboard/examples/index.html.erb_spec.rb
@@ -0,0 +1,26 @@
+require "rails_helper"
+require "nokogiri"
+
+module Dashboard
+ RSpec.describe "/dashboard/examples/index", type: :view do
+ before(:each) do
+ assign(:examples, [
+ Example.create!(
+ text: "Word",
+ body: "Sentence"
+ ),
+ Example.create!(
+ text: "Word",
+ body: "Sentence"
+ )
+ ])
+ end
+
+ it "renders a list of examples" do
+ render
+ cell_selector = Rails::VERSION::STRING >= "7" ? "div>p" : "tr>td"
+ assert_select cell_selector, text: Regexp.new("Word".to_s), count: 2
+ assert_select cell_selector, text: Regexp.new("Sentence".to_s), count: 2
+ end
+ end
+end
diff --git a/spec/views/dashboard/examples/new.html.erb_spec.rb b/spec/views/dashboard/examples/new.html.erb_spec.rb
new file mode 100644
index 0000000..6d97650
--- /dev/null
+++ b/spec/views/dashboard/examples/new.html.erb_spec.rb
@@ -0,0 +1,22 @@
+require "rails_helper"
+
+module Dashboard
+ RSpec.xdescribe "dashboard/examples/new", type: :view do
+ before(:each) do
+ assign(:example, Example.new(
+ text: "MyString",
+ body: "MyText"
+ ))
+ end
+
+ it "renders new example form" do
+ render
+
+ assert_select "form[action=?][method=?]", examples_path, "post" do
+ assert_select "input[name=?]", "example[text]"
+
+ assert_select "textarea[name=?]", "example[body]"
+ end
+ end
+ end
+end
diff --git a/spec/views/dashboard/examples/show.html.erb_spec.rb b/spec/views/dashboard/examples/show.html.erb_spec.rb
new file mode 100644
index 0000000..5049e5e
--- /dev/null
+++ b/spec/views/dashboard/examples/show.html.erb_spec.rb
@@ -0,0 +1,18 @@
+require "rails_helper"
+
+module Dashboard
+ RSpec.describe "dashboard/examples/show", type: :view do
+ before(:each) do
+ assign(:example, Example.create!(
+ text: "Word",
+ body: "Sentence"
+ ))
+ end
+
+ it "renders attributes in " do
+ render
+ expect(rendered).to match(/Word/)
+ expect(rendered).to match(/Sentence/)
+ end
+ end
+end