Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implementation of Phlex::Rails::Actions #104

Closed
wants to merge 1 commit into from

Conversation

bradgessler
Copy link
Contributor

I was about to put this in a REST-related gem, but I realized this probably belongs in phlex-rails. Phlex::Rails::Actions makes it possible to do this in a controller, thus making it possible to build a Rails app entirely out of Phlex components (look mah, no Erb!)

class PostsController < ApplicationController
  resources :posts, from: :current_user

  class Form < ApplicationForm
    def template
      labeled field(:title).input.focus
      labeled field(:publish_at).input
      labeled field(:content).textarea(rows: 6)

      submit
    end
  end

  class Index < ApplicationView
    attr_writer :posts, :current_user

    def title = "#{@current_user.name}'s Posts"

    def template
      render TableComponent.new(items: @posts) do |table|
        table.column("Title") { show(_1, :title) }
        table.column do |column|
          # Titles might not always be text, so we need to handle rendering
          # Phlex markup within.
          column.title do
            link_to(user_blogs_path(@current_user)) { "Blogs" }
          end
          column.item { show(_1.blog, :title) }
        end
      end
    end
  end

  class Show < ApplicationView
    attr_writer :post

    def title = @post.title
    def subtitle = show(@post.blog, :title)

    def template
      table do
        tbody do
          tr do
            th { "Status" }
            td { @post.status }
          end
          tr do
            th { "Publish at" }
            td { @post.publish_at&.to_formatted_s(:long) }
          end
          tr do
            th { "Content" }
            td do
              article { @post.content }
            end
          end
        end
      end
      nav do
        edit(@post, role: "button")
        delete(@post)
      end
    end
  end

  class Edit < ApplicationView
    attr_writer :post

    def title = @post.title
    def subtitle = show(@post.blog, :title)

    def template
      render Form.new(@post)
    end
  end

  private

  def destroyed_url
    @post.blog
  end
end

There's a whole working blog demo at https://demo.rubymonolith.com and the source at https://github.com/rubymonolith/demo/tree/main that shows this working. I also wrote an article about it at https://fly.io/ruby-dispatch/component-driven-development-on-rails-with-phlex/ that provides a little more context.

Not mentioned in any thing I've written so far: it is possible for a controller to co-exist with method names and classes for actions. The methods take precedence over the class names.

@bradgessler bradgessler marked this pull request as draft July 27, 2023 06:00
@bradgessler
Copy link
Contributor Author

Oops, started this not-as-a-draft. I still need to write specs that test the controller integration.

Feedback and comments are still welcome!

@bradgessler bradgessler force-pushed the phlex-rails-actions branch 7 times, most recently from 116cbd3 to 9983aea Compare July 27, 2023 07:03
@bradgessler bradgessler marked this pull request as ready for review July 27, 2023 07:13
@bradgessler
Copy link
Contributor Author

Specs are passing, but the Linter is being a clown about a few things.

It's ready to merge!

@bradgessler
Copy link
Contributor Author

I'm moving this to https://github.com/rubymonolith/superview because there's a few other ideas I want to try for resolving views and setting instance variables.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant