komposable / komponent

An opinionated way of organizing front-end code in Ruby on Rails, based on components
http://komponent.io
MIT License
426 stars 31 forks source link

Rails 6 - undefined method `view_renderer=' #133

Closed agungyuliaji closed 5 years ago

agungyuliaji commented 5 years ago

How to reproduce:

Spone commented 5 years ago

Hi @agungyuliaji

which version of Komponent are you using?

Thanks in advance.

agungyuliaji commented 5 years ago

Hi @Spone it's ver. 2.2.0

Spone commented 5 years ago

Can you try with 3.0.0.beta1?

agungyuliaji commented 5 years ago

still same with 3.0.0.beta1, the core problem is, view_renderer= is not exist i've updated my PR, fix the test run, https://github.com/komposable/komponent/pull/134

but now I think maybe this is a little far away (since rails 6 is beta), maybe we can close this issue, and I will use the monkeypatch mode for my issue.

thanks bro 👊

Spone commented 5 years ago

Thanks for the feedback. I'll keep the issue open because it's weird our tests haven't detected the issue. I reopened #118 to update our tests to the new beta3.

Spone commented 5 years ago

Our tests were actually not run on Rails 6 :man_facepalming:

I managed to reproduce the issue in the tests: https://travis-ci.org/komposable/komponent/jobs/511340428

0x2C6 commented 5 years ago

Same problem here :D It should also be good if it moves and renames javascript to frontend and also copy channels and other folders

0x2C6 commented 5 years ago

Okay, temporary solution. Clone the repo and move it to the application's lib folder update Gemfile and add

gem 'komponent', path: './lib/komponent'

Edit component_renderer file as below or just replace "view_renderer" instance variables to "render"

# frozen_string_literal: true

module Komponent
  class ComponentRenderer
    include ActionView::Helpers::CaptureHelper

    attr_accessor :output_buffer
    attr_reader :context

    def initialize(controller, view_flow = nil)
      @context = controller.view_context.dup
      @render = @context.view_renderer
      @lookup_context = @render.lookup_context = @render.lookup_context.dup
      @view_flow = view_flow
    end

    def render(component, locals = {}, options = {}, &block)
      cached = options.delete(:cached)
      if cached

        cached_block = block ? block.call : nil
        key = [component, locals, options, cached_block].to_s
        cache_key = Digest::SHA1.hexdigest(key)

        Rails.cache.fetch(cache_key) do
          _render(component, locals, options, &block)
        end
      else
        _render(component, locals, options, &block)
      end
    end

    private

    def _render(component, locals = {}, options = {}, &block)
      parts = component.split("/")
      component_name = parts.join("_")

      component_module_path = resolved_component_path(component)
        .join("#{component_name}_component")
      require_dependency(component_module_path)
      component_module = "#{component_name}_component".camelize.constantize

      @context.view_flow = @view_flow if @view_flow
      @context.class_eval { prepend component_module }
      @context.class_eval { prepend Komponent::Translation }

      @lookup_context.prefixes = ["components/#{component}"]

      @context.instance_eval do
        if component_module.respond_to?(:properties)
          locals = locals.dup
          component_module.properties.each do |name, options|
            unless locals.has_key?(name)
              if options.has_key?(:default)
                locals[name] = options[:default]
              elsif options[:required]
                raise "Missing required component parameter: #{name}"
              end
            end
          end
        end

        locals.each do |name, value|
          instance_variable_set(:"@#{name}", locals[name])
        end

        define_singleton_method(:properties) { locals }
        define_singleton_method(:block_given_to_component?) { block_given? }
        define_singleton_method(:block_given_to_component) { block }
      end

      @context.render("components/#{component}/#{parts.join('_')}", &block)
    end

    def resolved_component_path(component)
      Komponent::ComponentPathResolver.new.resolve(component)
    end
  end
end

Works for me on both 5.1.x and 6.0rc

alec-c4 commented 5 years ago

Hi! Maybe it would be better to create separate branch with this patch?