Giter Club home page Giter Club logo

buttercms-ruby's Introduction

ButterCMS API Ruby Client

Documentation

For a comprehensive list of examples, check out the API documentation.

Setup

To setup your project, follow these steps:

  1. Install using gem install buttercms-ruby or by adding to your Gemfile:
gem 'buttercms-ruby'
  1. Set your API token.
require 'buttercms-ruby'

ButterCMS::api_token = "YourToken"

# Fetch content from test mode (eg. for your staging website)
# ButterCMS::test_mode = true

# Set read timeout (Default is 5.0)
# ButterCMS::read_timeout = 5.0

# Set open timeout (Default is 2.0)
# ButterCMS::open_timeout = 2.0

Pages

https://buttercms.com/docs/api/?ruby#pages

params = {page: 1, page_size: 10, locale: 'en', preview: 1, 'fields.headline': 'foo bar', levels: 2} # optional
pages = ButterCMS::Page.list('news', params)

page = ButterCMS::Page.get('news', 'hello-world', params)

pages = ButterCMS::Page.search('query', params)

Collections

https://buttercms.com/docs/api/?ruby#retrieve-a-collection

# list each instance of a given collection with meta data for fetching the next page.
params = { page: 1, page_size: 10, locale: 'en', preview: 1, 'fields.headline': 'foo bar', levels: 2 } # optional
ButterCMS::Content.list('collection1', params)

# list instances for multiple collections, this will not return meta data for pagination control.
ButterCMS::Content.fetch(['collection1', 'collection2'], params)

# Test mode can be used to setup a staging website for previewing Collections or for testing content during local development. To fetch content from test mode add the following configuration:
ButterCMS::test_mode = true

Blog Engine

https://buttercms.com/docs/api/?ruby#blog-engine

posts = ButterCMS::Post.all({:page => 1, :page_size => 10})
puts posts.first.title
puts posts.meta.next_page

posts = ButterCMS::Post.search("my favorite post", {page: 1, page_size: 10})
puts posts.first.title

post = ButterCMS::Post.find("post-slug")
puts post.title

# Create a Post.
ButterCMS::write_api_token = "YourWriteToken"
ButterCMS::Post.create({
  slug: 'blog-slug',
  title: 'blog-title'
})

# Update a Post
ButterCMS::Post.update('blog-slug', {
  title: 'blog-title-v2'
})

# Create a page
ButterCMS::Page.create({
  slug: 'page-slug',
  title: 'page-title',
  status: 'published',
  "page-type": 'page_type',
  fields: {
    meta_title: 'test meta title'
  }
})

# update a Page
ButterCMS::Page.update('page-slug-2', {
  status: 'published',
  fields: {
    meta_title: 'test meta title'
  }
})



author = ButterCMS::Author.find("author-slug")
puts author.first_name

category = ButterCMS::Category.find("category-slug")
puts category.name

tags = ButterCMS::Tag.all
p tags

rss_feed = ButterCMS::Feed.find(:rss)
puts rss_feed.data

Fallback Data Store

This client supports automatic fallback to a data store when API requests fail. When a data store is set, on every successful API request the response is written to the data store. When a subsequent API request fails, the client attempts to fallback to the value in the data store. Currently, Redis and YAML Store are supported.

# Use YAMLstore
ButterCMS::data_store = :yaml, "/File/Path/For/buttercms.store"

# Use Redis
ButterCMS::data_store = :redis, ENV['REDIS_URL']

# Use Redis over ssl store
ButterCMS.data_store = :redis_ssl, ENV["REDIS_URL"], { ca_file: "/path/to/ca.crt" }

# Set logger (optional)
ButterCMS::logger = MyLogger.new

Other

View Ruby Blog engine and Full CMS for other examples of using ButterCMS with Ruby.

Development

buttercms-ruby's People

Contributors

bbugh avatar burlesona avatar chasecoleman avatar faheemmughal avatar gaffneyc avatar jakelumetta avatar jirkamotejl avatar kevinjcoleman avatar konnorrogers avatar orlyohreally avatar rogerjin12 avatar tskulkarni25 avatar violantecodes avatar zuzanawangle avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

buttercms-ruby's Issues

Post.find("invalid_id") returns invalid Post

This behavior changed in 1.1.2 with the switch to HTTParty. In version 1.1.1 trying to find an object that does not exist would raise a RestClient::ResourceNotFound exception, which was great because it was easy to catch inside of a Rails controller.

As of 1.1.2+ you get an invalid object.

ButterCMS::Post.find("invalid_id")
# => raises RestClient::ResourceNotFound
ButterCMS::Post.find("invalid_id")
=> #<ButterCMS::Post:0x3fec90b98af4> JSON: {
  "detail": "Not found."
}

ButterCMS::Post.find does not work correctly when slug includes a `#` character

Hello ButterCMS team,
I believe we discovered u bug regarding to find method. It is present in 2.0 and not present in 1.7. I didn't test version 1.8 and 1.9 specifically but I'm pretty confident that it was introduced in 2.0 - more on that later.

What happens?

When you run

ButterCMS::Post.find('#some-slug')

API client responds with

#<ButterCMS::Post:0x2af2bcb12c5c> JSON: {
  "detail": "Incorrect authentication credentials."
}

What did you expect to happen?

I expected that ButterCMS::NotFound (Not found.) will be raised, same as for non-existent slugs that do not include a #

Why does this happen?

I'm pretty sure I pinpointed the issue to this line.

Previously URI.encode_www_form_component was called, and it would encode the # in URL safe manner:

URI.encode_www_form_component('#ddff')
=> "%23ddff"

However it is not called any more, so the URL contains a raw #. When the request is made the HTTP client thinks this is beginning of the fragment part of the URL. This leads it to ignore the query part of the URL which includes the API key. This leads to auth_token param not being parsed correctly and we get the Incorrect authentication credentials. error back.

Please use semantic versioning or at least add a changelog

Hey ๐Ÿ‘‹
The most recent update upgrades the lib from 1.9 to 2.0. As far as I can see, the only thing that has changed iscompatibilityy with Ruby 3. Semantic versioning, which most open source libraries use, would suggest that a change from 1.9 to 2.0 involves large, breaking changes.

If for whatever reason you can't move to semver, please add a changelog so that customers like me don't need to start going through the code to try and work out what's changed between versions.

ButterCMS::Post.all method does not return all posts if the page_size param is 20 and preview is set

We currently have a combined total of 178 published and draft posts on butter.

Given this code

array = []
array += ButterCMS::Post.all(page_size: 100, page: 1, preview: 1).to_a
array += ButterCMS::Post.all(page_size: 100, page: 2, preview: 1).to_a
array.length => 178

That set of params correctly returns the number of posts into the array variable. I correctly get 178 back.
If I change the page_size param from 100 to 20, I'm missing two posts.

array = []
array += ButterCMS::Post.all(page_size: 20, page: 1, preview: 1).to_a
array += ButterCMS::Post.all(page_size: 20, page: 2, preview: 1).to_a
array += ButterCMS::Post.all(page_size: 20, page: 3, preview: 1).to_a
array += ButterCMS::Post.all(page_size: 20, page: 4, preview: 1).to_a
array += ButterCMS::Post.all(page_size: 20, page: 5, preview: 1).to_a
array += ButterCMS::Post.all(page_size: 20, page: 6, preview: 1).to_a
array += ButterCMS::Post.all(page_size: 20, page: 7, preview: 1).to_a
array += ButterCMS::Post.all(page_size: 20, page: 8, preview: 1).to_a
array += ButterCMS::Post.all(page_size: 20, page: 9, preview: 1).to_a
array.length => 176

I ran the code above with page_size ranging from 1 - 100 and it seems only the number 20 incorrectly returns the number of blog posts.

The bug does appear to occur only when I pass in the preview param in combination with page_size = 20.

fields.headline is not a valid hash key

Hi ๐Ÿ‘‹

There's some invalid Ruby code in a couple of places in the README. Listed is a hash key fields.headline: 'foo bar', which is not valid Ruby code.

params = { page: 1, page_size: 10, locale: 'en', preview: 1, fields.headline: 'foo bar', levels: 2 } # optional
                                                             ^^^^^^^^^^^^^^^

I assume from the API docs this is intended to be passed as a string like 'fields.headline' => 'foo bar' as a string. Is that correct?

params = { page: 1, page_size: 10, locale: 'en', preview: 1, "fields.headline" => 'foo bar', levels: 2 } # optional

map() Error

Unfortunately, it seems like in our haste to help, we actually made things worse!

The older PR filtered the path name through encode_www_form, which is expecting a Hash object (like query params)... but the path is a string, so this errors. The test suite also doesn't currently pass on the main branch.

PR incoming!

(Also, let us know if you want help setting up ruby CI for this project... would help with the tests!)


  1) ButterCMS.request raises NotFound on 404
     Failure/Error:
       expect { ButterCMS.request("/posts/slug/") }
         .to raise_error(ButterCMS::NotFound)
     
       expected ButterCMS::NotFound, got #<NoMethodError: undefined method `map' for "/posts/slug/":String
       Did you mean?  tap> with backtrace:
         # ./lib/buttercms-ruby.rb:74:in `api_request'
         # ./lib/buttercms-ruby.rb:99:in `request'
         # ./spec/lib/butter-ruby_spec.rb:32:in `block (4 levels) in <top (required)>'
         # ./spec/lib/butter-ruby_spec.rb:32:in `block (3 levels) in <top (required)>'
         # /Users/hcatlin/.rvm/gems/ruby-2.7.2/gems/webmock-3.11.2/lib/webmock/rspec.rb:37:in `block (2 levels) in <top (required)>'
     # ./spec/lib/butter-ruby_spec.rb:32:in `block (3 levels) in <top (required)>'
     # /Users/hcatlin/.rvm/gems/ruby-2.7.2/gems/webmock-3.11.2/lib/webmock/rspec.rb:37:in `block (2 levels) in <top (required)>'

  2) ButterCMS.request with an api token should make an api request
     Failure/Error: path = "#{@api_url.path}#{URI.encode_www_form(path)}?#{URI.encode_www_form(query)}"
     
     NoMethodError:
       undefined method `map' for "":String
       Did you mean?  tap
     # ./lib/buttercms-ruby.rb:74:in `api_request'
     # ./lib/buttercms-ruby.rb:99:in `request'
     # ./spec/lib/butter-ruby_spec.rb:14:in `block (4 levels) in <top (required)>'
     # /Users/hcatlin/.rvm/gems/ruby-2.7.2/gems/webmock-3.11.2/lib/webmock/rspec.rb:37:in `block (2 levels) in <top (required)>'

Finished in 0.02238 seconds (files took 0.17304 seconds to load)
14 examples, 2 failures

ButterCollection cannot be correctly marshal loaded because of dynamic method generation

We're using Rails cache to store our Butter API call results. The dynamically generated methods on ButterResource are not restored when restored from cache, leading to unreliable errors like NameError: undefined method seo_title' for #ButterCMS::Post:0x00007fec4faa2cb8`. This happens any time the server restarts.

Because of the way ButterResource is dynamically creating methods, the methods are not restored when a ButterCollection is restored from cache. Ruby only calls initialize on the main object when restoring via Marshal.load.

  • When restoring a ButterResource, the initialize method is called.
  • When restoring a ButterCollection, the initialize method of the ButterCollection is called, but not the internal ButterResources.

There's a couple different ways to fix this, which is why I am making an issue instead of a PR:

  1. Define the marshal_dump and marshal_load methods on ButterResource to dynamically add the methods in marshal_load. I think this is the only solution that preserves the current behavior
  2. Remove the dynamically defined methods and instead use method_missing to pass through the unknown calls to the @data OpenStruct. This could break existing code if people are checking for respond_to?

The marshal code would look something like this:

    # unfortunately, Ruby expects you to define both methods for this to work, 
    # so the dump has to be manually specified as well
    def marshal_dump
      { json: @json, data: @data, meta: @meta }
    end

    def marshal_load(dump)
      @json = dump[:json]
      @data = dump[:data]
      @meta = dump[:meta]

      return unless @data.respond_to?(:each_pair)

      @data.each_pair do |key, value|
        instance_variable_set("@#{key}", @data.send(key))
        self.class.send(:attr_reader, key)
      end
    end

I expect that the first option is the best for preserving backwards compatibility, what do you think?

Errors in Pages Ruby Code

When I run the code below, I would expect to get a list of pages back, instead I get this error:

p ButterCMS::Page.all('*')
Traceback (most recent call last):
        2: from (irb):11
        1: from (irb):12:in `rescue in irb_binding'
TypeError (no implicit conversion of Symbol into Integer)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.