Updating a page using script/runner

Dear All,

Thanks for the kind lessons on how to add a page using script/runner. I
have the following working script to create such a new page:

------ start of script to add a new page —

parent = Page.find_by_url(’/services/news’)
child = parent.children.build(:title => “Floods”,
:breadcrumb => “Floods”, :slug => “floods”)
child.parts.build(:content => “This is a page for flood news”,
:name => “body”)
child.save!

------ end of script to add a new page —

How may I update the contents using script/runner? I have tried
the following, but it does not work. Any help to solve this
would be much appreciated.

---- test script that does not work

floods = Page.find_by_url(’/services/news/floods’)
floods.parts.build(:content => “This is now for droughts”)
floods.update

thanks in advance,

saji

Saji,

You might try using “create” instead of “build”. In that case, it could
look like this:

parent = Page.find_by_url(‘/services/news’)
child = parent.children.create(:title => “Floods”, :breadcrumb =>
“Floods”, :slug => “floods”)
child.parts.create(:name => “body”, :content => “This is a page for
flood news”)

Keep in mind that create and build might not work if the collection is
empty or the original object is unsaved [1]. Your other alternative is
to build the objects manually, then push it into the collection:

parent = Page.find_by_url(‘/services/news’)
child = Page.new(:title => “Floods”, :breadcrumb => “Floods”, :slug =>
“floods”)
part = PagePart.new(:name => “body”, :content => “This is a page for
flood news”)
parent.children << child
child.parts << part

Also note in your second snippet that your part needs a name.

Sean

[1]

(if I’m interpreting the doc correctly)

Sean,

Thanks very much for the advice. On using “create” and then “update”,
I found that duplicate body “parts” were being “created” every time I
ran
the code. So running the script 5.times resulted in 5 “body parts” for
the
same page. After some experiments, here is what I found to suit my
purposes ( replacing a part of the page with new stuff). Esp. used
the “clear” method to wipe the page parts clean

------------

floods=Page.find_by_url(‘/services/news/floods’)
floods.parts.clear # wipe clear the flood page of its parts
floods.parts.create(
:content => “Now for floods and droughts”,
:name => “body”
)
floods.update

------------

saji

child.parts << part

Dear All,
:name => “body”)
floods = Page.find_by_url(‘/services/news/floods’)
Search: http://radiantcms.org/mailing-list/search/
Site: http://lists.radiantcms.org/mailman/listinfo/radiant


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


Saji N. Hameed

APEC Climate Center +82 51 668 7470
National Pension Corporation Busan Building 12F
Yeonsan 2-dong, Yeonje-gu, BUSAN 611705 [email protected]
KOREA

Saji,

Interesting, that would make sense. You could also do
floods.parts.find_or_initialize_by_name(“body”) if you don’t want to
drop the parts.

Sean

I’m resurrecting an old thread just before starting to look at it
myself. I’m likely to work on a project where it will be needed to
update a large number of pages. I think it may be possible to dump the
content out to a bunch of files from where it should be possible to pick
up the pages, add the usual stuff and update the pages to a Radiant site
using a script.

Is there anyone doing so using the script below or something similar?
Would it be possible to share?

I’ve never used script/runner with a live site but I’m willing to look
at the relevant stuff in the Rails world to make that happen. But I’m
just starting to wonder how to keep this site scalable (since it
involves the migration of about 7 books from PDF to Radiant) with a
bunch of relatively standard things to be included on each page.

Thanks,
Mohit.
12/19/2007 | 11:58 PM.

Thanks Saji,

It serves as a great example to see-and-learn!!

Cheers
Mohit.

Hi Mohit,

We control our own server, and it is easy to do stuff like this.
Here is a script that I use to update or add certain parts of our
website (currently offline).

Hope it is helpful.

saji

---------- %< start of code

#!/usr/bin/ruby
require File.dirname(FILE) + ‘/…/config/boot’
require ‘commands/runner’

class String
attr_accessor :slug
end

if ARGV.length==0
puts “USAGE : updateWeb YYYY MON service”
puts “for example : updateWeb 2007 NOV monitoring”
exit
end
months =%w( JAN FEB MAR APR MAY JUN JUL AUG SEP OCT NOV DEC)

def updateContents(pPage,cPage,cSlug,filter,parts,contents)
puts “Updating contents of #{pPage}/#{cPage}”
myPage = Page.find_by_url(pPage+“/”+cSlug)
myPage.parts.clear
nparts=parts.size
0.upto(nparts-1) do |i|
myPage.parts.create(
:content => contents[i],
:name => parts[i],
:filter_id => filter)
end
myPage.update
puts “Finished Updating”
end

def createPage(pPage,cPage,cSlug)
puts “Adding Page #{pPage}/#{cPage}”
parent=Page.find_by_url(pPage)
child = parent.children.create(
:title => cPage.capitalize,
:breadcrumb => cPage,
:slug => cSlug,
:status_id => “100”)
child.save!
end

def checkForPage(pPage,cPage,cSlug)
child= Page.find_by_url(pPage+“/”+cSlug)
neClass=child.class
if neClass==FileNotFoundPage
createPage(pPage,cPage,cSlug)
end
end

year=ARGV[0]
month=ARGV[1]
service=ARGV[2]
product=ARGV[2]

check and create reports page

case service
when “Monitoring”
service=service+“/Highlights/”
when “Prediction”
service=service+“/Outlook/”
when “ISV”
service=“Monitoring/Analysis/”+service+“/CurrentStatus/”
when “Drought”
service=“Monitoring/Analysis/”+service+“/CurrentStatus/”
end

For each part of the services string delimited by “/”

check for existence, if not create the page

servicePages = service.split(“/”)
pPage=“/services”
servicePages.each do |service|
servLow=service.downcase
cPage=service
cSlug=servLow
checkForPage(pPage,cPage,cSlug)
pPage=pPage+“/”+servLow
end

check and create reports/YYYY page

cPage=year
cSlug=cPage
checkForPage(pPage,cPage,cSlug)
body=<<END_OF_BODY
<r:children:first>
<r:content />
</r:children:first>
END_OF_BODY

sidebar=<<END_OF_SIDEBAR

Archives By Month

<r:find url=“#{pPage}”>
<r:content part=“sidebar” />
</r:find>
END_OF_SIDEBAR

parts=[“body”,“sidebar”]
contents=[body,sidebar]
filter=“”
updateContents(pPage,cPage,cSlug,filter,parts,contents)

check and create reports/YYYY/MON page

pPage=pPage+“/”+cSlug
cPage=month
cSlug=(months.index(month) + 1).to_s
checkForPage(pPage,cPage,cSlug)

check this directory and upload text files and image files separately

product=“/Reports/#{product}/#{year}/#{month}”
prodDir=File.dirname(FILE)+“/…/public/#{product}”
allFiles=ls #{prodDir}.split

txtFiles=[]
allFiles.each { |a| txtFiles.push([a]) unless File.extname(a)==“.png”}
exit if txtFiles.size==0
exit if txtFiles.size>1
imgFiles=[]
allFiles.each { |a| imgFiles.push([a]) if File.extname(a)==“.png”}
exit if imgFiles.size==0

txtFile=txtFiles.first.join
content=File.read(prodDir+“/”+txtFile)
txt=<<END_OF_TXT
<r:content part=“image” />
END_OF_TXT
content=content + “\n”+ txt
img_describe=“

parts=[“body”,“image”]
contents=[content,img_describe]
filter=“Maruku”
updateContents(pPage,cPage,cSlug,filter,parts,contents)

------- %< end of code

I’ve never used script/runner with a live site but I’m willing to look

flood news")
parent.children << child
Saji Njarackalazhikam H. wrote:

:breadcrumb => “Floods”, :slug => “floods”)

---- test script that does not work

Radiant mailing list
Search: http://radiantcms.org/mailing-list/search/
Site: http://lists.radiantcms.org/mailman/listinfo/radiant

Saji N. Hameed

APEC Climate Center +82 51 668 7470
National Pension Corporation Busan Building 12F
Yeonsan 2-dong, Yeonje-gu, BUSAN 611705 [email protected]
KOREA

Saji N Hameed wrote:

Hi Mohit,

We control our own server, and it is easy to do stuff like this.
Here is a script that I use to update or add certain parts of our
website (currently offline).

Hope it is helpful.

saji

Looking at this answers the fundamental question I had!! I was
concerned about how the authentication is handled to get past the
admin. But, of course, when we use script/runner, we’re usually
accessing the models directly rather than through the controllers - and
the controllers are where the before_filters for authentication will
usually be!

That said, I guess this means that it’s best for the script to be local
to the site - so, I can’t get it to submit from my desktop to the server
machine. The script should ideally be on the server where the site is
running.

Is this how you’re using it, Saji?

Cheers,
Mohit.
12/20/2007 | 12:33 AM.

machine. The script should ideally be on the server where the site is
running.

Is this how you’re using it, Saji?

Well, the web-server is a different machine, but we have
full access to it. We run a drb server on the
web-server and installed clients on other machines. Users upload
stuff from their desktops to the webserver through this mechanism.

I remember Sean’s advise that you may be able to use Capistrano
for this purpose. That may be worth checking out.

Anyway, I am attaching scripts for the client and servers
we use.

best wishes,
saji

— this is the drb server that sits at the web-server

#!/usr/bin/env ruby

require ‘drb’
require ‘drb/acl’

@baseDir=ENV[‘RadiantHOME’]+“/customScripts”

this order is important, so do not move the

the require statement below

require File.join(File.dirname(FILE), ‘server_methods’)

puts “Will Exit if not executed in right Directory”
exit unless pwd.chomp == @baseDir

if FILE == $0
acl = ACL.new(%w( deny all allow 190.1.1.121 allow 220.84.94.58 allow
localhost ) )
DRb.install_acl(acl)
DRb.start_service(“druby://:7777”, OurClass.new)
puts “Drb server running at #{DRb.uri}”
trap(“INT”) {DRb.stop_service }
DRb.thread.join
end

— some methods used by the DRb object

require ‘net/ftp’

class OurClass

def chDir(wDir,year,month)
wDir=“/home/saji/MyTestServer/public/Reports/”+wDir+“/”+year+“/”+month
mkdir -p #{wDir}
@wDir=wDir
end

def ftpFiles(ftpsite,login,password,wDir,txt,img)
“Opening new ftp session for #{ftpsite}”
ftp=Net::FTP.new(ftpsite)
ftp.login(user=login,passwd=password)
ftp.chdir(wDir)
“Retrieving Image files”
ftp.getbinaryfile(img,@wDir+“/”+img)
“Retrieving Text files”
ftp.gettextfile(txt,@wDir+“/”+txt)
ftp.close
“ftp over”
end

def updateWeb(service,year,month)
# run an update
retVal=[]
ENV[‘RAILS_ENV’]=“production”
ls = IO.popen(“…/script/runner updateWeb #{year} #{month}
#{service}”,“r”)
while line = ls.gets
retVal << line
puts line
end
ls.close
return(retVal)
end

end

— The ncurses based client that is used to upload information to the

web-page via DRb server

#!/usr/bin/env ruby
require “rdialog”
require ‘drb’

@months=%w(JAN FEB MAR APR MAY JUN JUL AUG SEP OCT NOV DEC)
dialog = RDialog.new
dialog.nocancel = true
@thisMonth=@months[Time.today.mon - 1]
@thisYear=Time.today.year.to_s

def updateWebPage
meSg = @webServer.updateWeb(@product,@year,@month)
dialog = RDialog.new
dialog.nocancel = true
dialog.shadow = false
tst=dialog.infobox(meSg, height=0, width=0)
end

def interactWithRemoteServer
@webServer = DRbObject.new nil, ‘druby://190.1.1.24:7777’
@webServer.chDir(@product,@year,@month)
wDir=@wDir+“/”+@year+“/”+@month
[email protected](@ftpsite,@login,@password,wDir,@txt,@img)
dialog = RDialog.new
dialog.nocancel = true
dialog.shadow = false
tst=dialog.msgbox(meSg, height=0, width=0)
updateWebPage
end

def findLoginDetails
dialog = RDialog.new
dialog.nocancel = true
dialog.shadow = false
@ftpsite = dialog.inputbox(text=“IP address of your machine”,
height=20,width=60, init=“190.1.1.121”)
defLogin=whoami.chomp
@login = dialog.inputbox(text=“Your login”, height=0,width=0,
init=defLogin)
@password = dialog.passwordbox(text=“Enter your password”,
height=0,width=0,init=“”)
end

def checkFiles
dialog = RDialog.new
dialog.nocancel = true
dialog.shadow = false
allFiles=ls.split
txtFiles=[]
allFiles.each { |a| txtFiles.push([a]) unless File.extname(a)==“.png”}
exit if txtFiles.size==0
myText = dialog.radiolist(text=“Chose Text Files”, items=txtFiles)
imgFiles=[]
allFiles.each { |a| imgFiles.push([a]) if File.extname(a)==“.png”}
exit if imgFiles.size==0
myImgs = dialog.checklist(text=“Chose Image Files”, items=imgFiles)
@txt = myText
@img = myImgs[0]

findLoginDetails
interactWithRemoteServer
end

def prepareForTransport
dialog1 = RDialog.new
dialog1.nocancel = true
dialog1.shadow = false
Dir.chdir(@wDir)
myDate = dialog1.calendar(text=“Select a Date”, height=0, width=0,
day=-1, month=Date.today.mon(), year=Date.today.year())
myMonth = myDate.mon()
myYear = myDate.year
@month = @months[myMonth - 1]
@year = myYear.to_s
Dir.chdir(@year)
Dir.chdir(@month)
checkFiles
end

prod_type = Array.new
prod_type.push([“Monitoring Highlights”])
prod_type.push([“Prediction Outlook”])
prod_type.push([“ISV Highlights”])
prod_type.push([“Drought Highlights”])

services = dialog.checklist(“Chose a Service”,prod_type)

for service in services
prefix = service.split[0]
workDir=ENV[“CIS_#{prefix.upcase}”]
exit if workDir==nil
exit unless File.exist?(workDir)
@wDir=workDir
@product=prefix
prepareForTransport
end


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


Saji N. Hameed

APEC Climate Center +82 51 668 7470
National Pension Corporation Busan Building 12F
Yeonsan 2-dong, Yeonje-gu, BUSAN 611705 [email protected]
KOREA