README.md in fmrest-0.2.0 vs README.md in fmrest-0.2.1
- old
+ new
@@ -12,11 +12,12 @@
anyway).
If you're looking for a Ruby client for the legacy XML/Custom Web Publishing
API try the fabulous [ginjo-rfm gem](https://github.com/ginjo/rfm) instead.
-fmrest-ruby does not currently implement the full spec of FileMaker Data API.
+fmrest-ruby does not currently implement the full spec of FileMaker 17's Data
+API.
## Installation
Add this line to your Gemfile:
@@ -139,11 +140,11 @@
```
And finally extend your Spyke models with `FmRest::Spyke`:
```ruby
-class Kitty < Spyke::Base
+class Honeybee < Spyke::Base
include FmRest::Spyke
end
```
This will make your Spyke model send all its requests in Data API format, with
@@ -153,41 +154,39 @@
Alternatively you can inherit directly from the shorthand
`FmRest::Spyke::Base`, which is in itself a subclass of `Spyke::Base` with
`FmRest::Spyke` already included:
```ruby
-class Kitty < FmRest::Spyke::Base
+class Honeybee < FmRest::Spyke::Base
end
```
In this case you can pass the `fmrest_config` hash as an argument to `Base()`:
```ruby
-class Kitty < FmRest::Spyke::Base(host: "...", database: "...", username: "...", password: "...")
+class Honeybee < FmRest::Spyke::Base(host: "...", database: "...", username: "...", password: "...")
end
-Kitty.fmrest_config # => { host: "...", database: "...", username: "...", password: "..." }
+Honeybee.fmrest_config # => { host: "...", database: "...", username: "...", password: "..." }
```
All of Spyke's basic ORM operations work:
```ruby
-kitty = Kitty.new
+bee = Honeybee.new
-kitty.name = "Felix"
+bee.name = "Hutch"
+bee.save # POST request
-kitty.save # POST request
+bee.name = "ハッチ"
+bee.save # PATCH request
-kitty.name = "Tom"
+bee.reload # GET request
-kitty.save # PATCH request
+bee.destroy # DELETE request
-kitty.reload # GET request
-
-kitty.destroy # DELETE request
-
-kitty = Kitty.find(9) # GET request
+bee = Honeybee.find(9) # GET request
```
Read Spyke's documentation for more information on these basic features.
In addition `FmRest::Spyke` extends `Spyke::Base` subclasses with the following
@@ -196,27 +195,27 @@
### Model.fmrest_config=
Usually to tell a Spyke object to use a certain Faraday connection you'd use:
```ruby
-class Kitty < Spyke::Base
+class Honeybee < Spyke::Base
self.connection = Faraday.new(...)
end
```
fmrest-ruby simplfies the process of setting up your Spyke model with a Faraday
connection by allowing you to just set your Data API connection settings:
```ruby
-class Kitty < Spyke::Base
+class Honeybee < Spyke::Base
include FmRest::Spyke
self.fmrest_config = {
host: "example.com",
- database: "database name",
- username: "username",
- password: "password"
+ database: "My Database",
+ username: "...",
+ password: "..."
}
end
```
This will automatically create a proper Faraday connection for those connection
@@ -225,33 +224,33 @@
Note that these settings are inheritable, so you could create a base class that
does the initial connection setup and then inherit from it in models using that
same connection. E.g.:
```ruby
-class KittyBase < Spyke::Base
+class BeeBase < Spyke::Base
include FmRest::Spyke
self.fmrest_config = {
host: "example.com",
database: "My Database",
- username: "username",
- password: "password"
+ username: "...",
+ password: "..."
}
end
-class Kitty < KittyBase
- # This model will use the same connection as KittyBase
+class Honeybee < BeeBase
+ # This model will use the same connection as BeeBase
end
```
### Model.layout
Use `layout` to set the `:layout` part of API URLs, e.g.:
```ruby
-class Kitty < FmRest::Spyke::Base
- layout "FluffyKitty" # uri path will be "layouts/FluffyKitty/records(/:id)"
+class Honeybee < FmRest::Spyke::Base
+ layout "Honeybees Web" # uri path will be "layouts/Honeybees%20Web/records(/:id)"
end
```
This is much preferred over using Spyke's `uri` to set custom URLs for your
Data API models.
@@ -266,106 +265,101 @@
since they may sometimes contain spaces and other special characters, so
fmrest-ruby extends `attributes`' functionality to allow you to map
Ruby-friendly attribute names to FileMaker field names. E.g.:
```ruby
-class Kitty < FmRest::Spyke::Base
+class Honeybee < FmRest::Spyke::Base
attributes first_name: "First Name", last_name: "Last Name"
end
```
You can then simply use the pretty attribute names whenever working with your
model and they will get mapped to their FileMaker fields:
```ruby
-kitty = Kitty.find(1)
+bee = Honeybee.find(1)
-kitty.first_name # => "Mr."
-kitty.last_name # => "Fluffers"
+bee.first_name # => "Princess"
+bee.last_name # => "Buzz"
-kitty.first_name = "Dr."
+bee.first_name = "Queen"
-kitty.attributes # => { "First Name": "Dr.", "Last Name": "Fluffers" }
+bee.attributes # => { "First Name": "Queen", "Last Name": "Buzz" }
```
### Model.has_portal
You can define portal associations on your model as such:
```ruby
-class Kitty < FmRest::Spyke::Base
- has_portal :wool_yarns
+class Honeybee < FmRest::Spyke::Base
+ has_portal :flowers
end
-class WoolYarn < FmRest::Spyke::Base
- attributes :color, :thickness
+class Flower < FmRest::Spyke::Base
+ attributes :color, :species
end
```
In this case fmrest-ruby will expect the portal table name and portal object
-name to be both "wool_yarns". E.g., the expected portal JSON portion should be
-look like this:
+name to be both "flowers", i.e. the expected portal JSON portion should look
+like this:
```json
...
"portalData": {
- "wool_yarns": [
+ "flowers": [
{
- "wool_yarns::color": "yellow",
- "wool_yarns::thickness": "thick",
+ "flowers::color": "red",
+ "flowers::species": "rose"
}
]
}
```
If you need to specify different values for them you can do so with
`portal_key` for the portal table name, and `attribute_prefix` for the portal
-object name, e.g.:
+object name, and `class_name`, e.g.:
```ruby
-class Kitty < FmRest::Spyke::Base
- has_portal :wool_yarns, portal_key: "Wool Yarn", attribute_prefix: "WoolYarn"
+class Honeybee < FmRest::Spyke::Base
+ has_portal :pollinated_flowers, portal_key: "Bee Flowers",
+ attribute_prefix: "Flower",
+ class_name: "Flower"
end
```
-The above expects the following portal JSON portion:
+The above will use the `Flower` model class and expects the following portal JSON
+portion:
```json
...
"portalData": {
- "Wool Yarn": [
+ "Bee Flowers": [
{
- "WoolYarn::color": "yellow",
- "WoolYarn::thickness": "thick",
+ "Flower::color": "white",
+ "Flower::species": "rose"
}
]
}
```
-You can also specify a different class name with the `class_name` option:
-
-```ruby
-class Kitty < FmRest::Spyke::Base
- has_portal :wool_yarns, class_name: "FancyWoolYarn"
-end
-```
-
### Dirty attributes
fmrest-ruby includes support for ActiveModel's Dirty mixin out of the box,
providing methods like:
```ruby
-kitty = Kitty.new
+bee = Honeybee.new
-kitty.changed? # => false
+bee.changed? # => false
-kitty.name = "Mr. Fluffers"
+bee.name = "Maya"
-kitty.changed? # => true
+bee.changed? # => true
-kitty.name_changed? # => true
+bee.name_changed? # => true
```
fmrest-ruby uses the Dirty functionality to only send changed attributes back
to the server on save.
@@ -378,155 +372,155 @@
passing arbitrary parameters to the REST backend. fmrest-ruby however is well
aware of its backend API, so it extends Spkye models with a bunch of useful
querying methods.
```ruby
-class Kitty < Spyke::Base
+class Honeybee < Spyke::Base
include FmRest::Spyke
- attributes name: "CatName", age: "CatAge"
+ attributes name: "Bee Name", age: "Bee Age"
- has_portal :toys, portal_key: "CatToys"
+ has_portal :hives, portal_key: "Bee Hives"
end
```
#### .limit
`.limit` sets the limit for get and find request:
```ruby
-Kitty.limit(10)
+Honeybee.limit(10)
```
#### .offset
`.offset` sets the offset for get and find requests:
```ruby
-Kitty.offset(10)
+Honeybee.offset(10)
```
#### .sort
`.sort` (or `.order`) sets sorting options for get and find requests:
```ruby
-Kitty.sort(:name, :age)
-Kitty.order(:name, :age) # alias method
+Honeybee.sort(:name, :age)
+Honeybee.order(:name, :age) # alias method
```
You can set descending sort order by appending either `!` or `__desc` to a sort
attribute (defaults to ascending order):
```ruby
-Kitty.sort(:name, :age!)
-Kitty.sort(:name, :age__desc)
+Honeybee.sort(:name, :age!)
+Honeybee.sort(:name, :age__desc)
```
#### .portal
`.portal` (or `.includes`) sets the portals to fetch for get and find requests
(this recognizes portals defined with `has_portal`):
```ruby
-Kitty.portal(:toys)
-Kitty.includes(:toys) # alias method
+Honeybee.portal(:hives)
+Honeybee.includes(:hives) # alias method
```
#### .query
`.query` sets query conditions for a find request (and supports attributes as
defined with `attributes`):
```ruby
-Kitty.query(name: "Mr. Fluffers")
-# JSON -> {"query": [{"CatName": "Mr. Fluffers"}]}
+Honeybee.query(name: "Hutch")
+# JSON -> {"query": [{"Bee Name": "Hutch"}]}
```
Passing multiple attributes to `.query` will group them in the same JSON object:
```ruby
-Kitty.query(name: "Mr. Fluffers", age: 4)
-# JSON -> {"query": [{"CatName": "Foo", "CatAge": 4}]}
+Honeybee.query(name: "Hutch", age: 4)
+# JSON -> {"query": [{"Bee Name": "Hutch", "Bee Age": 4}]}
```
Calling `.query` multiple times or passing it multiple hashes creates separate
JSON objects (so you can define OR queries):
```ruby
-Kitty.query(name: "Mr. Fluffers").query(name: "Coronel Chai Latte")
-Kitty.query({ name: "Mr. Fluffers" }, { name: "Coronel Chai Latte" })
-# JSON -> {"query": [{"CatName": "Mr. Fluffers"}, {"CatName": "Coronel Chai Latte"}]}
+Honeybee.query(name: "Hutch").query(name: "Maya")
+Honeybee.query({ name: "Hutch" }, { name: "Maya" })
+# JSON -> {"query": [{"Bee Name": "Hutch"}, {"Bee Name": "Maya"}]}
```
#### .omit
`.omit` works like `.query` but excludes matches:
```ruby
-Kitty.omit(name: "Captain Whiskers")
-# JSON -> {"query": [{"CatName": "Captain Whiskers", "omit": "true"}]}
+Honeybee.omit(name: "Hutch")
+# JSON -> {"query": [{"Bee Name": "Hutch", "omit": "true"}]}
```
You can get the same effect by passing `omit: true` to `.query`:
```ruby
-Kitty.query(name: "Captain Whiskers", omit: true)
-# JSON -> {"query": [{"CatName": "Captain Whiskers", "omit": "true"}]}
+Honeybee.query(name: "Hutch", omit: true)
+# JSON -> {"query": [{"Bee Name": "Hutch", "omit": "true"}]}
```
#### Other notes on querying
You can chain all query methods together:
```ruby
-Kitty.limit(10).offset(20).sort(:name, :age!).portal(:toys).query(name: "Mr. Fluffers")
+Honeybee.limit(10).offset(20).sort(:name, :age!).portal(:hives).query(name: "Hutch")
```
You can also set default values for limit and sort on the class:
```ruby
-Kitty.default_limit = 1000
-Kitty.default_sort = [:name, :age!]
+Honeybee.default_limit = 1000
+Honeybee.default_sort = [:name, :age!]
```
Calling any `Enumerable` method on the resulting scope object will trigger a
server request, so you can treat the scope as a collection:
```ruby
-Kitty.limit(10).sort(:name).each { |kitty| ... }
+Honeybee.limit(10).sort(:name).each { |bee| ... }
```
If you want to explicitly run the request instead you can use `.find_some` on
the scope object:
```ruby
-Kitty.limit(10).sort(:name).find_some # => [<Kitty...>, ...]
+Honeybee.limit(10).sort(:name).find_some # => [<Honeybee...>, ...]
```
If you want just a single result you can use `.find_one` instead (this will
force `.limit(1)`):
```ruby
-Kitty.query(name: "Mr. Fluffers").find_one # => <Kitty...>
+Honeybee.query(name: "Hutch").find_one # => <Honeybee...>
```
NOTE: If you know the id of the record you should use `.find(id)` instead of
`.query(id: id).find_one` (so that the request is sent as `GET ../:layout/records/:id`
instead of `POST ../:layout/_find`).
```ruby
-Kitty.find(89) # => <Kitty...>
+Honeybee.find(89) # => <Honeybee...>
```
### Container fields
You can define container fields on your model class with `container`:
```ruby
-class Kitty < FmRest::Spyke::Base
- container :photo, field_name: "Vet Card Photo ID"
+class Honeybee < FmRest::Spyke::Base
+ container :photo, field_name: "Beehive Photo ID"
end
```
`:field_name` specifies the original field in the FM layout and is optional, if
not given it will default to the name of your attribute (just `:photo` in this
@@ -536,17 +530,17 @@
addition to the `container` definition.)
This will provide you with the following instance methods:
```ruby
-kitty = Kitty.new
+bee = Honeybee.new
-kitty.photo.url # The URL of the container file on the FileMaker server
+bee.photo.url # The URL of the container file on the FileMaker server
-kitty.photo.download # Download the contents of the container as an IO object
+bee.photo.download # Download the contents of the container as an IO object
-kitty.photo.upload(filename_or_io) # Upload a file to the container
+bee.photo.upload(filename_or_io) # Upload a file to the container
```
`upload` also accepts an options hash with the following options:
* `:repetition` - Sets the field repetition
@@ -573,16 +567,16 @@
password: "abc123",
log: true
}
# Or in your model
-class LoggyKitty < FmRest::Spyke::Base
+class LoggyBee < FmRest::Spyke::Base
self.fmrest_config = {
host: "example.com",
database: "My Database",
- username: "z3r0c00l",
- password: "abc123",
+ username: "...",
+ password: "...",
log: true
}
end
```
@@ -591,10 +585,10 @@
If you need to set up more complex logging for your models can use the
`faraday` block inside your class to inject your own logger middleware into the
Faraday connection, e.g.:
```ruby
-class LoggyKitty < FmRest::Spyke::Base
+class LoggyBee < FmRest::Spyke::Base
faraday do |conn|
conn.response :logger, MyApp.logger, bodies: true
end
end
```