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…</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