2

Rails アプリにWordPress のショートコードの概念を(多かれ少なかれ) 実装しています。問題は、ビューで:yield定義されたレイアウトで何かを行うcontent_forと、それが空白になることです。そのため、追加の JavaScript タグとタイトル タグはレンダリングされません。

つまり、レイアウトで呼び出すcontent_for? :titleと false が返されます。

これだけ起こる投稿/インデックスで、ログインしている場合のみ filter_shortcodesヘルパーが実行されたとき。誰もこのようなことに遭遇したことがありますか?

ビュー/投稿/index.html.haml:

- content_for :script do
    = javascript_include_tag '/assets/autoload.js'

- content_for :title do
    Blog
...
= render template: 'article-content',

そして、views/article-content.html.haml (filter_shortcodesShortcodeモジュールで定義されたヘルパー関数です):

:plain
    #{filter_shortcodes instance.content}

問題は私のショートコード モジュールにあると私は確信しています。

module Shortcode
    def filter_shortcodes content
        content.gsub /(?<!\\)\[.+\]/ do |code|
            # A shortcode must:
            #   - be on its own line
            #   - be [contained within square brackets]
            #   - be named using only lowercase letters
            # If it contains parameters, they must come in the form:
            #   key="value"
            shortcode = /^\s*\[(?<name>[a-z]+) (?<params>.*)\s*\]\s*$/.match code

            params_list = shortcode[:params].gsub /&quot;|"/, '"'

            param_regexp = /([a-z]+)="([^"]*)"/
            shortcode_params = {}
            params_list.scan param_regexp do |param|
                shortcode_params[param[0].to_sym] = param[1]
            end

            render_to_string template: "shortcodes/#{shortcode[:name]}",
                :locals => shortcode_params, layout: false
        end
    end
end
4

1 に答える 1

1

ショートコードモジュールに問題があること判明しました。基本的に、render_to_stringrender のように動作し、コントローラー アクションでいずれかを 1 回だけ呼び出すことができます。そのためfilter_shortcode、コントローラー メソッドとして動作していたため (コントローラー クラスにモジュールを含めることにより)、render_to_string1 回限りのプリンシパルに違反していました。

Rails がrender2 回呼び出しを試みたときと同じようにこれを強制してくれるとよいのですが、これは特殊なケースでしょうか?

とにかく、私の解決策は、テンプレートの代わりにセルをレンダリングすることでした。以下のコードはもう少し冗長ですが、ショートコード固有の検証を実行できるため、より堅牢です。

ライブラリ/ショートコード.rb:

module Shortcode
    def filter_shortcodes content

        # A shortcode must:
        #   - be on its own line
        #   - be [contained within square brackets]
        #   - be named using only lowercase letters
        #   - be unescaped (not preceded by a "\")
        # If it contains parameters, they must come in the form:
        #   key="value"
        regex = /^\s*\[(?<name>[\w]+)\s+(?<params>([^\]]+\s*)*)?\](?<contents>([^\[])*)?(\[(\\|\/)[a-z]+\])?$/

        # Here's the negative lookbehind for the escaping \
        content.gsub /(?<!\\)\[.+\]/ do |code|

            shortcode = regex.match code
            # return shortcode[:params]
            params = get_params shortcode
            params[:contents] = shortcode[:contents] if shortcode[:contents].present?

            if ShortcodeCell.method_defined? shortcode[:name]
                # just spit out the content if the template doesn't exist
                begin
                    render_cell :shortcode, shortcode[:name], params
                rescue ArgumentError => error
                    "[#{shortcode[:name]} ERROR: #{error.message}]"
                end
            else
                "Unsupported shortcode: #{shortcode[:name]}"
            end
        end
    end

    def get_params shortcode
        # hack to render quotes...
        params_list = shortcode[:params].gsub /&quot;|"/, '"'

        params = {}
        params_list.scan /([a-z]+)="([^"]*)"/ do |param|
            params[param[0].to_sym] = param[1]
        end

        return params
    end

セル/ショートコード_cell.rb:

class ShortcodeCell < Cell::Rails
    def soundcloud args
        if args[:url].blank?
            raise ArgumentError.new 'missing URL'
        end

        render locals: args
    end
end
于 2013-11-06T20:10:20.873 に答える