Walter Lee Davis wrote:
I posted a question yesterday about the Mailer extension, and it occurs to me that it might have come off too "needy". I am just starting with Rails and Ruby, and stumbled across Radiant, which can already do about 80% of what I need "out of the box". Could someone tell me, in general terms, if I will need to learn to fully develop in Rails before I can do things like validate a form submission within Radiant? Does being able to create an extension equate with being able to create a Rails app? Or will I be able to skate along without coming all the way up that learning curve, and learn as I have always done, by picking apart other people's solutions and modifying them to my needs?

Learning Rails would definitely help you understand how Radiant works, but Radiant does a number of things on it's own that aren't particularly Railsish. Creating your own extensions would definitely help you get the hang of Radiant, but unfortunately documentation is a bit thin right now so you will probably need to resort to reading the source code more often than not. Studying the way other extensions are written will also help.

Sorry not to answer your other question right away. In general if you want a form in Radiant that displays error messages you need to create a number of tags for displaying error messages.

Here's an example from a small plugin I wrote for the Ruby Lang Web site to simplify subscribing to the Ruby-Mailing lists:

<r:subscribe>
  <r:unless_success>
    Mailing-lists are a great way to keep your finger on the pulse of
    the Ruby community.

    <r:form id="subscriptions-form">
      <h2>Subscribe or Unsubscribe</h2>

      <r:if_error><p class="error"><r:error_message /></p></r:if_error>

      <p>
        Mailing List:   <r:list_select /><br />
        First Name:     <r:first_name_input /><br />
        Last Name:      <r:last_name_input /><br />
        E-mail Address: <r:email_input /><br />
        Action:         <r:action_select />
      </p>
      <div class="buttons">
        <input class="button" type="submit" value="Submit Form" />
      </div>
    </r:form>
  </r:unless_success>

  <r:if_success>
    <h2>Confirmation E-mail</h2>
    <p>You should receive a confirmation message within a few minutes.
      Once you have received the message, follow the instructions it
      contains to complete the process.</p>
    <p><r:link>Subscribe to another mailing list&#8230;</r:link></p>
  </r:if_success>
</r:subscribe>

You can see this in action here:

http://www.ruby-lang.org/en/community/mailing-lists/

In a nutshell the form tag on the Subscribe page submits to the current URL. The Subscribe page then has a chance to process the request. It checks for a post and if it's a post it processes the request. If there are no errors it sets success to true and the part in the <r:if_success> tags renders. If it can't process the form because their are errors it sets the error message and that will be displayed above the form.

Extremely messy, I know, especially by Rails standards, but this is the cleanest implementation I could come up with that worked with tags.

I've attached the complete Behavior for your perusal that was designed to work with 0.5.2. It works slightly differently on mental and the 0.6 release candidates because behaviors have been merged with the Page class, but this is the general idea.

--
John Long
http://wiseheartdesign.com
require 'behavior'
require 'mailing_list_mailer'

class SubscribeBehavior < Behavior::Base

  register 'Subscribe'

  define_tags do
    tag "subscribe" do |tag|
      tag.expand
    end

    tag "subscribe:form" do |tag|
      a = tag.attr.dup
      list = a.delete('list')
      attrs = attributes(a, 'action' => tag.globals.page.url, 'method' => 'post')
      %{<form#{attrs}>#{tag.expand}</form>}
    end

    tag "subscribe:form:first_name_input" do |tag|
      attrs = attributes(tag.attr, 'name' => 'first_name', 'value' => first_name)
      %{<input#{attrs} />}
    end

    tag "subscribe:form:last_name_input" do |tag|
      attrs = attributes(tag.attr, 'name' => 'last_name', 'value' => last_name)
      %{<input#{attrs} />}
    end

    tag "subscribe:form:email_input" do |tag|
      attrs = attributes(tag.attr, 'name' => 'email', 'value' => email)
      %{<input#{attrs} />}
    end

    tag "subscribe:form:action_select" do |tag|
      attrs = attributes(tag.attr, 'name' => 'action')
      options = ['Subscribe', 'Unsubscribe'].map do |opt|
        selected = %{ selected="true"} if opt.downcase == action
        %{<option value="#{opt.downcase}"#{selected}>#{opt}</option>}
      end
      %{<select#{attrs}>#{options.join}</select>}
    end
    
    tag "subscribe:form:list_select" do |tag|
      attrs = attributes(tag.attr, 'name' => 'list')
      lists = List.find_all
      options = lists.map do |list|
        name = list.name
        selected = %{ selected="true"} if name.downcase == list_name.downcase
        %{<option value="#{name.downcase}"#{selected}>#{name}</option>}
      end
      %{<select#{attrs}>#{options.join}</select>}
    end

    tag "subscribe:if_error" do |tag|
      tag.expand if error?
    end

    tag "subscribe:unless_error" do |tag|
      tag.expand unless error?
    end

    tag "subscribe:error_message" do |tag|
      error_message
    end

    tag "subscribe:if_success" do |tag|
      tag.expand if success
    end

    tag "subscribe:unless_success" do |tag|
      tag.expand unless success
    end

    tag "subscribe:if_success:list_name" do |tag|
      list_name
    end
  end

  def render_page
    if request.post?
      @list       = List.lookup(params[:list] || 'ruby-talk')
      @first_name = get_param(:first_name)
      @last_name  = get_param(:last_name)
      @email      = get_param(:email)
      @action     = get_param(:action).downcase
      if @action =~ /^(subscribe|unsubscribe)$/
        if @list
          unless @first_name.blank? or @last_name.blank?
            if @email =~ /^[^@;[EMAIL PROTECTED]@;\s]+\.[^@;\s]+$/
              case action
              when "subscribe"
                MailingListMailer.deliver_subscribe_message(@first_name, @last_name, @email, @list)
              when "unsubscribe"
                MailingListMailer.deliver_unsubscribe_message(@email, @list)
              end
              @success = true
            else
              @error_message = 'Invalid e-mail address.'
            end
          else
            @error_message = 'Please enter a first name and last name.'
          end
        else
          @error_message = 'Invalid list.'
        end
      else
        @error_message = 'Invalid action.'
      end
    else
      @success = false
    end
    super
  end

  def cache_page?
    false
  end

  class List
    attr_accessor :name, :post_address, :ctl_address

    def initialize(name, post_address = nil, ctl_address = nil)
      @name = name
      @post_address = post_address || "[EMAIL PROTECTED]"
      @ctl_address = ctl_address || "[EMAIL PROTECTED]"
    end

    def self.find_all
      ['Ruby-Talk', 'Ruby-Core', 'Ruby-Doc', 'Ruby-CVS'].map { |name| new(name) }
    end

    def self.lookup(name)
      lists = find_all.inject({}) { |h, l| h[l.name.downcase] = l; h }
      lists[name.to_s.strip.downcase]
    end
  end

  private

    def params
      @params ||= request.params.inject({}) { |h,(k,v)| h[k.to_s.intern] = v.first; h }
    end

    def get_param(param)
      (params[param] || '').strip
    end

    def attributes(tag_attrs, defaults)
      defaults.dup.update(tag_attrs).map { |k,v| %{ #{k}="#{v}"} }.join
    end

    def first_name
      @first_name || ''
    end

    def last_name
      @last_name || ''
    end

    def email
      @email || ''
    end

    def action
      @action || ''
    end

    def list_name
      if @list
        @list.name
      else
        ''
      end
    end

    def success
      @success
    end

    def error?
      [EMAIL PROTECTED]
    end

    def error_message
      (@error_message || '').strip
    end

end
_______________________________________________
Radiant mailing list
Post:   [email protected]
Search: http://radiantcms.org/mailing-list/search/
Site:   http://lists.radiantcms.org/mailman/listinfo/radiant

Reply via email to