Security News
Research
Data Theft Repackaged: A Case Study in Malicious Wrapper Packages on npm
The Socket Research Team breaks down a malicious wrapper package that uses obfuscation to harvest credentials and exfiltrate sensitive data.
Opinionated presenters for Rails 5 - without the cruft.
If you've ever worked on a sufficiently large Rails application you've probably experienced the Rails helper mess first hand. Helper methods are annoying to locate, hard to test and not terribly expressive.
So why another presenter/decorator library? Oprah was written with a few simple goals in mind only covered partially (or not at all) by other gems:
SimpleDelegator
Add this line to your application's Gemfile:
gem 'oprah'
And then execute:
$ bundle
Oprah expects a single presenter for each of your classes or modules. If your
model is called User
it will look for a class called UserPresenter
:
class User
def first_name
"John"
end
def last_name
"Doe"
end
end
class UserPresenter < Oprah::Presenter
def name
"#{first_name} #{last_name}"
end
end
Oprah will figure out the presenters by itself so you don't have to instantiate your presenter classes directly:
presenter = Oprah.present(User.new)
presenter.name
# => "John Doe"
Of course, all the regular methods on your model are still accessible:
presenter.first_name
# => "John"
If you DO want to use a specific presenter, you can simply instantiate it yourself:
SomeOtherPresenter.new(User.new)
Now, where do we put our presenters? Ideally, you'd want to expose them in your controller. Oprah avoids monkey patching and generally it's good to be aware of what's going on, even if that means to be (at least a little bit) explicit.
Here's how you can use Oprah presenters from your controller:
class UsersController < ApplicationController
def show
@user = present User.find(params[:id])
end
end
This will also take care of passing the correct view context to the presenter,
which you can access with the #view_context
(or shorter, #h
) instance
method.
Oprah will make the same helpers you have in ActionController available to ActionMailer:
class UserMailer < ApplicationMailer
default from: 'notifications@example.com'
def welcome_email(user)
@user = present user
mail(to: @user.email, subject: 'Welcome to My Awesome Site')
end
end
Oprah has basic support for collections with .present_many
. It will simply
apply it's .present
behavior to each object in the given collection:
users = [User.new, User.new]
presenters = Oprah.present_many(users)
presenters.first.kind_of?(UserPresenter)
# => true
presenters.last.kind_of?(UserPresenter)
# => true
Of course, this works in controllers, too:
class UserController < ApplicationController
def index
@users = present_many User.all
end
end
You can also automatically use presenters for your associations using the
#presents_one
and #presents_many
macros. Let's say you have the following
Project
model:
class Project
has_many :users
has_one :owner, class_name: "User"
end
Oprah lets you easily wrap the associated objects:
class ProjectPresenter < Oprah::Presenter
presents_many :users
presents_one :owner
end
Note that you don't need to explicitly state the association class.
Let's say you extraced some behaviour out of your model into a reusable module (or
ActiveSupport::Concern
). Oprah lets you write a single, separate presenter for
this module and automatically chains it to your "main presenter" by walking up the
ancestor chain of the given object.
Let's say we want to mix a shared Describable
module into our User
class from
above and render the description to HTML:
module Describable
def description
"*AWESOME*"
end
end
class User
include Describable
end
class DescribablePresenter < Oprah::Presenter
def description
Kramdown::Document.new(object.description).to_html
end
end
You can now access the methods of both, UserPresenter
and
DescribablePresenter
:
presenter = Oprah.present(User.new)
presenter.description
=> "<p><em>AWESOME</em></p>\n"
presenter.name
# => John Doe
Of course, looking up all the presenters would imply a performance issue. But don't worry, Oprah caches all matching presenters for a class (and busts it's cache on code reloads for a smooth development experience).
Oprah walks your object's ancestor chain in reverse. For example, you'd be
able to access the methods exposed by the DescribablePresenter
from your
UserPresenter
. You can even use super
:
class DescribablePresenter < Oprah::Presenter
def baz
"foo"
end
end
class UserPresenter < Oprah::Presenter
def baz
super + "bar"
end
end
Oprah.present(User.new).baz
# => "foobar"
When presenting an object you can optionally choose which presenter classes to use:
Oprah.present(User.new, only: DescribablePresenter)
This parameter takes either a single presenter or an Array
of presenters.
The presenter(s) given need to match the object's class or one of it's
ancestors. Non-matching presenters given will be ignored.
Testing presenters is as simple as testing a regular class. Oprah also provides couple of helpers to make it even easier:
class UserPresenterTest < Minitest::Test
include Oprah::TestHelpers
def setup
@presenter = present User.new
end
def test_presented
assert_presented @presenter
end
def test_name
assert_equal "John Doe", @presenter.name
end
end
Comprehensive API Documentation is available at rubydoc.info.
Please check out our contributing guidelines.
Released under the MIT license. See the LICENSE file for details.
Tobias Svensson, @endofunky, http://github.com/endofunky
FAQs
Unknown package
We found that detaso-oprah demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Research
The Socket Research Team breaks down a malicious wrapper package that uses obfuscation to harvest credentials and exfiltrate sensitive data.
Research
Security News
Attackers used a malicious npm package typosquatting a popular ESLint plugin to steal sensitive data, execute commands, and exploit developer systems.
Security News
The Ultralytics' PyPI Package was compromised four times in one weekend through GitHub Actions cache poisoning and failure to rotate previously compromised API tokens.