getting active records to display as a plist - ruby

I'm trying to get a list of active record results to display as a plist for being consumed by the iphone. I'm using the plist gem v 3.0.
My model is called Post. And I want Post.all (or any array or Posts) to display correctly as a Plist.
I have it working fine for one Post instance:
[http://pastie.org/580902][1]
that is correct, what I would expect. To get that behavior I had to do this:
class Post < ActiveRecord::Base
def to_plist
attributes.to_plist
end
end
However, when I do a Post.all, I can't get it to display what I want. Here is what happens:
http://pastie.org/580909
I get marshalling. I want output more like this:
[http://pastie.org/580914][2]
I suppose I could just iterate the result set and append the plist strings. But seems ugly, I'm sure there is a more elegant way to do this.
I am rusty on Ruby right now, so the elegant way isn't obvious to me. Seems like I should be able to override ActiveRecord and make result-sets that pull back more than one record take the ActiveRecord::Base to_plist and make another to_plist implementation. In rails, this would go in environment.rb, right?

I took the easy way out:
private
# pass in posts resultset from finds
def posts_to_plist(posts)
plist_array = []
posts.each do |post|
plist_array << post.attributes
end
plist_array.to_plist
end
public
# GET /posts
# GET /posts.xml
def index
#posts = Post.all
##posts = [{:a=>"blah"}, {:b=>"blah2"}]
respond_to do |format|
format.html # index.html.erb
format.xml { render :xml => posts_to_plist(#posts) }
end
end

I found this page searching for the same answer. I think you have the right approach, though I'm also a newbie (on Rails) and not sure the right way to do it. I added this to application_helper.rb. Seems to work.
require 'plist'
module ApplicationHelper
class ActiveRecord::Base
public
include Plist::Emit
def to_plist
self.attribute_names.inject({}) do |attrs, name|
value = self.read_attribute(name)
if !value.nil?
attrs[name] = value
end
attrs
end
end
end
end

According to the plist project README, you should implement "to_plist_node", as opposed to "to_plist".
You should also mixin Plist::Emit to your ActiveRecord class.

Related

Ruby ERB - Create a content_for method

I'm currently working on an ERB View class for a gem. With this class I would like to have some helper methods for ERB templates.
It's okay about basic helpers like h(string). I found erbh gem who help me to understand more how context works.
But now I'm trying to create a content_for method like there is in Rails or Sinatra.
On first time I was using simple Proc to capture the view block and then just calling call method to print it. It was working enough at the beginning.
But after having completed views I saw wired thinks, some content are printed multiple times.
So I take a look on the Sinatra ContentFor helper to understand how they did it and I copy some methods of this helper. I have no errors, but the block return are always empty... and I don't really know why.
My knowledge about ERB are not good enough to know how ERB buffering works.
Code
Here a gist who explain the status of my code. I extracted the code from my library and simplified it a bit.
https://gist.github.com/nicolas-brousse/ac7f5454a1a45bae30c52dae826d587f/66cf76c97c35a02fc6bf4a3bc13d8d3b587356de
What I would like?
I just would like to have content_for methods works like they do with Rails and Sinatra.
Thanks!
After reading this blog article I finally found why it wasn't working. I don't know if I did it in the best way and cleaner way but it works.
So the bug was mainly from the ERB initilization. By using a property instead a local variable as eoutvar it now works.
erb = ERB.new(str, nil, "<>", "#_erbout")
I also change a bit the capture method who is used by content_for helper.
It looks like this now (gist)
def content_for(key, content = nil, &block)
block ||= proc { |*| content }
content_blocks[key.to_sym] << capture_later(&block)
end
def content_for?(key)
content_blocks[key.to_sym].any?
end
def yield_content(key, default = nil)
return default if content_blocks[key.to_sym].empty?
content_blocks[key.to_sym].map { |b| capture(&b) }.join
end
def capture(&block)
#capture = nil
#_erbout, _buf_was = '', #_erbout
result = yield
#_erbout = _buf_was
result.strip.empty? && #capture ? #capture : result
end
def capture_later(&block)
proc { |*| #capture = capture(&block) }
end

How to map routes to controllers in Sinatra?

I'd like to create a simple experimental MVC framework using Sinatra.
I'd like to define resources by name "pages" for example should resolve to:
/pages (index)
/pages/new
/pages/:id/show (show)
as WELL as map to app/controllers/PagesController.rb with corresponding get('/') to be responsible for the index, post('/pages/create') be responsible for creation, etc.
Trouble is even after reading the official documentation I'm terribly confused. I imagine I need to use non-classic Sinatra model for this, but could anyone point me in the right direction?
Thank you
If you want what I think you're wanting, I do this all the time. Initially for this scheme I used the travis-api source as a reference, but essentially what you want to do is extend Sinatra::Base in a "controller" class and then mount up your individual Sinatra "controllers" in rack, something like this:
module Endpoint
def self.included(base)
base.class_eval do
set(:prefix) { "/" << name[/[^:]+$/].downcase }
end
end
end
class Users < Sinatra::Base
include Endpoint
get '/' do
#logic here
end
get '/:id' do
#logic here
end
post '/' do
#logic here
end
patch '/:id' do
#logic here
end
end
class Posts < Sinatra::Base
include Endpoint
post '/' do
#logic here
end
end
and then something like this:
class App
require "lib/endpoints/users"
require "lib/endpoints/posts"
attr_reader :app
def initialize
#app = Rack::Builder.app do
[Users, Posts].each do |e|
map(e.prefix) { run(e.new) }
end
end
end
def call(env)
app.call(env)
end
end
You can adjust this to whatever you need, but the idea is the same, you separate your app into composable Sinatra applications that each have a prefix that they are mounted under using Rack. This particular example will give you routes for:
get '/users'
get '/users/:id'
post '/users'
patch '/users/:id'
get '/posts'
I'll give you a very simple example here:
Create a file controller.rb
get '/pages' do
#pages = Pages.all
erb :pages
end
Next create a views directory in the same folder as teh controller, and create a file named pages.html.erb
This is the corresponding view to your previously created controller action.
Here, you can type something like:
<% #pages.each do |p| %>
<%= p.title %>
<% end %>
Restart your server, visit localhost:PORT/pages and you will see a list of all your page titles.
You can check out this link for a simple sinatra tutorial - http://code.tutsplus.com/tutorials/singing-with-sinatra--net-18965
You can make this as complicated or as simple as you need. For example:
Rails makes a lot of magic happen under the hood, whereas Sinatra is more flexible at the cost of requiring you to implement some of this stuff yourself.
controller_map = {
'pages' => PagesController
}
post '/:controller/new' do
c = params[:controller]
module = controller_map[c]
module.create_new()
...
end
get '/:controller/:id/show' do
c = params[:controller]
id = params[:id]
module = controller_map[c]
module.get(id)
...
end

Best way to DRY up code using procs and blocks and/or dynamic methods

I am writing a way to parse websites, each "scraper" has it's own way gather information, but there is plenty of common functionality between two methods.
Differences:
One scraper uses Nokogiri to open the page via css selectors
the other scraper uses an RSS feed to gather information
Similarities:
each scraper creates an "Event" object that has the following attributes:
title
date
description
if for the Nokogiri scraper, we do something like this:
event_selector = page.css(".div-class")
event_selector.each_with_index do |event, index|
date = Date.parse(event.text) #code I want to share
end
for the RSS scraper, we do something like this
open(url) do |rss|
feed = RSS::Parser.parse(rss)
feed.items.each do |event|
description = Sanitize.fragment(event.description)
date = description[/\d{2}-\d{2}-20\d{2}/]
date = Date.strptime(date, '%m-%d-%Y') #code I want to share
end
end
^^ The date is grabbed via a regex from the description and then converted into a Date object via the .strptime method
as you can see each scraper uses 2 different method calls/ways to find the date. How could I abstract this information into a class?
I was thinking of something like this:
class scrape
attr_accessor :scrape_url, :title, :description, :date, :url
def initialize(options = {})
end
def find_date(&block)
# Process the block??
end
end
and then in each of the scraper methods do something like
scrape = Scrape.new
date_proc = Proc.new {Date.parse(event.text)}
scrape.find_date(date_proc)
Is this the right way to go about this problem? In short I want to have common functionality of two website parsers to pass the desired code into a instance method of a "scrape" class. I would greatly appreciate any tips to tackle this scenario.
Edit: Maybe it would make more sense if I say that I want to find the "date" of an event, but the way I find it - the behavior - or the specific code that is run, is different.
You could use an Event builder. Something like this:
class Event::Builder
def date(raw)
#date = Date.strptime(raw, '%m-%d-%Y')
end
# ... more setters (title, description) ...
def build
Event.new(date: #date, ... more arguments ..)
end
end
And then, inside the scraper:
open(url) do |rss|
builder = Event::Builder.new
feed = RSS::Parser.parse(rss)
feed.items.each do |event|
description = Sanitize.fragment(event.description)
date = description[/\d{2}-\d{2}-20\d{2}/]
builder.date(date)
# ... set other attributes ...
event = builder.build
# do something with the event ...
end
end
You should look into the Strategy or Template patterns. These are ways of writing code that does different things depending on some state or configuration. Essentially you'd write a Scraper class and then sub class it as WebScraper and RssScraper. Each class would inherit from the Scraper class all the common functionality but only differ in their implementation of how to get the date, description, etc.

Ruby Devise 2.2 add email address along with the user.email

Currently I am using ruby devise gem 2.2.3. And I tried to customize the confirmation_instructions for adding couple of email ids with the user email.
app/mailers/my_devise_mailer.rb
class MyDeviseMailer < Devise::Mailer
include Devise::Mailers::Helpers
def confirmation_instructions(record, opts={})
opts[:to] = "example1#mail.com, example2#mail.com"
super
end
end
config/initializers/devise.rb
config.mailer = "MyDeviseMailer"
And, I ran the following in my console
user = User.first
MyDeviseMailer.delay.confirmation_instructions(user)
I got a output without body message. PFA
Correct
Wrong
Can anyone tell me what I missed to add/configure?
You could create a new mailer instead and modify the headers of that one:
# app/mailers/my_mailer.rb
class MyMailer < Devise::Mailer
def headers_for(action, opts)
if action == :confirmation_instructions
super.merge!(to: ['example1#mail.com', 'example2#mail.com'])
else
super
end
end
end
Then tell Devise to use your mailer:
# config/initializers/devise.rb
config.mailer = MyMailer
super.merge!" will not work. Because it'll replace the value for the given key (:to). But, the requirement is to add two mail id's with 'To'. The following gist is working fine.
class MyMailer < Devise::Mailer
include Devise::Mailers::Helpers
def headers_for(action, opts={})
begin
super.merge!(to: [super[:to], 'example1#mail.com', 'example2#mail.com'], template_path: ["devise/mailer"]) if action == :confirmation_instructions
rescue Exception => e
super
end
end
end
Happy Coding!!

Two versions of each blog post in Jekyll

I need two versions of each of my posts in a very simple Jekyll setup: The public facing version and a barebones version with branding specifically for embedding.
I have one layout for each type:
post.html
post_embed.html
I could accomplish this just fine by making duplicates of each post file with different layouts in the front matter, but that's obviously a terrible way to do it. There must be a simpler solution, either at the level of the command line or in the front matter?
Update:
This SO question covers creating JSON files for each post. I really just need a generator to loop through each post, alter one value in the YAML front matter (embed_page=True) and feed it back to the same template. So each post is rendered twice, once with embed_page true and one with it false. Still don't have a full grasp of generators.
Here's my Jekyll plugin to accomplish this. It's probably absurdly inefficient, but I've been writing in Ruby for all of two days.
module Jekyll
# override write and destination functions to taking optional argument for pagename
class Post
def destination(dest, pagename)
# The url needs to be unescaped in order to preserve the correct filename
path = File.join(dest, CGI.unescape(self.url))
path = File.join(path, pagename) if template[/\.html$/].nil?
path
end
def write(dest, pagename="index.html")
path = destination(dest, pagename)
puts path
FileUtils.mkdir_p(File.dirname(path))
File.open(path, 'w') do |f|
f.write(self.output)
end
end
end
# the cleanup function was erasing our work
class Site
def cleanup
end
end
class EmbedPostGenerator < Generator
safe true
priority :low
def generate(site)
site.posts.each do |post|
if post.data["embeddable"]
post.data["is_embed"] = true
post.render(site.layouts, site.site_payload)
post.write(site.dest, "embed.html")
post.data["is_embed"] = false
end
end
end
end
end

Resources