I'm using tabulatr2 to handle table alike data. However I can't wrap my head around how to include pundit's policy checks in tabulatr2's data definition.
So I have something akin to
class MystuffTabulatrData < Tabulatr::Data
column :blah
buttons do |b,r|
if policy(r).destroy? # XXX: NoMethodError - undefined method `policy' for #<Data::Proxy:0x83f84bb0>
...
end
end
end
One usually uses something like <%= table_for Mystuff %> in a view.
Since we work with Data::Proxy there, the source suggests that #controller should be available. So #controller.policy(r) works just fine.
Related
I need to handle a particular case of generating email views with URLs constructed from non-persisted data.
Example : assume my user can create posts, and that triggers a post creation notification email, I'd like to send the user an example of fake post creation. For this, I am using a FactoryGirl.build(:post) and passing this to my PostMailer.notify_of_creation(#post)
In everyday Rails life, we use the route url_helpers by passing as argument the model itself, and the route generator will automatically convert the model into its ID to be used for the route URL generation (in article_path(#article), the routes helper converts #article into #article.id for constructing the /articles/:id URL.
I believe it is the same in ActiveRecord, but anyways in Mongoid, this conversion fails if the model is not persisted (and this is somewhat nice as it prevents the generation of URLs that may not correspond to actual data)
So in my specific case, URL generation crashes as the model is not persisted:
<%= post_url(#post_not_persisted) %>
crashes with
ActionView::Template::Error: No route matches {:action=>"show", :controller=>"posts", :post_id=>#<Post _id: 59b3ea2aaba9cf202d4eecb6 ...
Is there a way I can bypass this limitation only in a very specific scope ? Otherwise I could replace all my resource_path(#model) by resource_path(#model.id.to_s) or better #model.class.name but this doesn't feel like the right situation...
EDIT :
The main problem is
Foo.new.to_param # => nil
# whereas
Foo.new.id.to_s # => "59b528e8aba9cf74ce5d06c0"
I need to force to_param to return the ID (or something else) even if the model is not persisted. Right now I'm looking at refinements to see if I can use a scoped monkeypatch but if you have better ideas please be my guest :-)
module ForceToParamToUseIdRefinement
refine Foo do
def to_param
self.class.name + 'ID'
end
end
end
However I seem to have a small scope problem when using my refinement, as this doesn't bubble up as expected to url_helpers. It works fine when using te refinement in the console though (Foo.new.to_param # => 59b528e8aba9cf74ce5d06c0)
I found a way using dynamic method override. I don't really like it but it gets the job done. I am basically monkeypatching the instances I use during my tests.
To make it easier, I have created a class method example_model_accessor that basically behaves like attr_accessor excepts that the setter patches the #to_param method of the object
def example_model_accessor(model_name)
attr_reader model_name
define_method(:"#{model_name}=") do |instance|
def instance.to_param
self.class.name + 'ID'
end
instance_variable_set(:"##{model_name}", instance)
end
end
Then in my code I can just use
class Testing
example_model_accessor :message
def generate_view_with_unpersisted_data
self.message = FactoryGirl.build(:message)
MessageMailer.created(message).deliver_now
end
end
# views/message_mailer/created.html.erb
...
<%= message_path(#message) %> <!-- Will work now and output "/messages/MessageID" ! -->
I use jsonapi-resources gem in my Rails app. One of my resources is using pagination. There are cases when I want to disable the pagination and make sure that user will get back all the results.
I tried custom implementation with some custom filter, but failed.
I tried passing "weird" values to paginator, but that did not help (examples for paged paginator):
/api/v1/bars?page[size]=-1 - value not allowed
/api/v1/bars?page[size]=0 - value not allowed
/api/v1/bars?page[size]=999999 - sure, this might work, but it is 100%
i got exactly the same problem today and found this unanswered question.
Below is how I dealt with the problem.
class CustomPaginator < PagedPaginator
attr_reader :limit, :offset, :disable_pagination
def initialize(params)
#disable_pagination = params.nil?
super
end
def apply(relation, _order_options)
disable_pagination ? relation : super
end
end
and in the resources I wanted to use the CustomPaginator I just added paginator :custom like below:
class UserResource < JSONAPI::Resource
paginator :custom
....user implementation
end
now whenever i want to use the paginator i need to explicitly use paginations params when I do the request to the server and when I don't use them I will get full unpaginated response.
The class implementation is not perfect (duh!) but it's just to show you the general concept
I've come up with an issue I can't figure out how to solve. I'm new to both Ruby and Rails, and sure there is a simple way to achieve what I'm looking for.
This is the ERB of the show view, showing two equal lines:
<p><%= #user.foo %></p>
<p><%= #user.foo %></p>
Imagine that foo is an intense computational method so I want to cache the result of the first call in order to use it in the second line without having to call foo again. The simplest option would be defining a variable and cache it:
<% foo_cache = #user.foo %>
<p><%= foo_cache %></p>
<p><%= foo_cache %></p>
But I don't want to clutter the "global" scope. A nicer way would be that foo itself could save a cache of the value it returns when it's called the first time:
def foo
return self.cached_foo if self.cached_foo #WARNING: pseudocode here!
#Not cached. Do stuff
...
self.cached_foo = computed_value
computed_value
end
My question is if it's possible to attach data to an object instance dynamically without interfering with the model behind (i.e. without making save and company functions deal with this attached data). Or maybe is there another better way to achieve what I'm looking for?
Thanks.
This is called memoization and it's a common idiom in ruby. It is usually expressed like this:
def foo
#cached_foo ||= begin
# do your heavy stuff here
end
end
#cached_foo should not interfere with ActiveRecord (like make it try to save cached_foo to the database).
What you are looking for is called memoization
def foo
#foo ||= calculate_foo
end
def calculate_foo
# heavy stuff
end
This works thanks to conditional assignment (the||=)
It's an extensive topic so I'll leave you a couple of links about it:
http://rails-bestpractices.com/posts/59-use-memoization
http://gavinmiller.io/2013/basics-of-ruby-memoization/
Plus advanced memoization in case you need to do more complicated stuff such as parameters, storing nil values
http://gavinmiller.io/2013/advanced-memoization-in-ruby/
In fact Active Support had memoizable but it was deprecated and then extracted into a gem
In case you want to use it check it out on:
https://github.com/matthewrudy/memoist
This should do it. And don't be afraid, the instance variable has no impact on the persistence layer.
def foo
#foo ||= compute_foo
end
private
def compute_foo
# ...
end
I'm trying to understand how to properly use memcache in my rails app.
Currently, in my header view of my app, I have a conditional like so:
<% if current_user.company.stats == true %>
So everytime any page loads, its hitting the database to check if the current user's company has statistics enabled.
This of course seems crazy to me.
So my question is, how should I be using memcache to resolve this. Companies rarely change, so data relating to them should be cached.
I understand something like this would cache them all:
def self.all_cached
Rails.cache.fetch('Company.all') { all }
end
But I know thats not what I need here - right?
Memcached can be seen as a big map key-value.
You should write something like this in your view:
<% if stats_enabled?(current_user.company) %>
And then write an helper method (on ApplicationHelper, for example):
def stats_enabled?(company)
Company.stats_enabled?(company)
end
and an cache method on you model:
class Company < ActiveRecord::Base
...
def self.stats_enabled?(company)
return Rails.cache.fetch(company.id) {
Company.find(company.id).stat
}
end
...
end
I've done a lot of research on this topic and there seems to be some dispute, so I wanted to get your opinions. Here is my basic situation - I have a User model:
class User < ActiveRecord::Base
# User consists of first_name, last_name, and other fields
has_one :profile # 1-1 mapping between User and Profile
# Profile is a nested resource of User
# this is the method up for debate:
# this obviously doesn't work unless I include
# the necessary modules in this class
def link(*args)
link_to self.first_name, users_profile_path(self), args
end
end
My reasoning for this kind of behavior is that, in my views, I'd like to do something like:
<%= #user.link %>
instead of:
<%= link_to #user.name, users_profile_path(#user) ... %>
every time. This link will be used thousands of times, in many different views. I want to centralize this "method" so that, when I need to make a change, I can make it once.
However, this practice absolutely violates the MVC architecture. Others suggest using a helper:
module UsersHelper
def profile_link(user, *args)
link_to user.name, users_profile_path(user), args
end
end
Now, I have to wrap the user in the method instead of calling it as a method ON user:
<%= profile_link(#user) %>
Which, in my opinion, is uglier than the latter example.
So my question is - which is better?? Or is there a way to accomplish this that I'm completely unaware of?
Rails is all about coding by convention. As you've pointed out, using a method in the model breaks the conventions of MVC. Unless there's a compelling reason to do so, you're better off going with the flow, and using the helper approach.
One practical issue is testing: you'll find it easier to test the helper method than the model method. Helper tests will include the link_to and users_profile_path methods for you -- model tests won't.
Finally, think of other developers reading your code. Where would they expect to find this method? If you follow MVC, you'll make their lives easier.
Use the helper. Because this is a method that creates a view object (the anchor tag), it's best to put it in a helper module.
Take a look at ActiveRecord's to_param method: http://api.rubyonrails.org/classes/ActiveRecord/Base.html#method-i-to_param