What's a proper way of using enum-type attributes in Rails 3? - ruby

Simple example might be a Post, that has three states, DRAFT, PUBLISHED and DELETED.
The way I do this right now is something like:
class Post < ActiveRecord::Base
DRAFT = 0
PUBLISHED = 1
DELETED = 2
end
The problem that arises is that when I'm running my tests using spork, I have to reload the model manualy, with something like
Spork.each_run do
Dir["#{Rails.root}/app/models/**/*.rb"].each { |model| load model }
end
Which in result gives me loads of warnings like
warning: already initialized constant DRAFT
warning: already initialized constant PUBLISHED
warning: already initialized constant DELETED
Everything works just fine, but I don't think this is the best way to do this. Is there a better way to do this? I know there are gems like acts_as_state_machine, but I'd like to know a non-gem solution if there is a simple one.

Related

ActiveStorage::Attachment find resource by blob_id

I have the following model
class Document
has_many_attached :previews
...
end
And I'm trying to find single elements there.
The problem is if I do:
#document.previews.find_by(blob_id: 22)
I get this error: undefined method `find_by' for #<ActiveStorage::Attached::Many>
So I'm kind of forced to loop through enumerable:
#document.previews.find { |p| p.blob_id == 22 }
Is there any other (better/prettier) way to do this?
#ntonnelier I have a similar model, and with Rails 7.0.3 your first example works fine for me:
#document.previews.find_by(blob_id: 22)
Another couple of options that work are:
#document.previews.where(blob_id: 22)
#document.previews.blobs.find_by_id(22)
You should be able to access the blobs for a particular record via the blobs method, which gets you an ActiveRecord collection, and you can use find on that one.
Something like #document.previews.blobs.find(22) might work in your particular case.

How to call a method on a local variable in Ruby?

Probably a stupid question but I was following along this article and came across a bit of code I couldn't quite grasp. Here it is:
class CreateArticle
attr_reader :validate_article, :persist_article
def initialize(validate_article, persist_article)
#validate_article = validate_article
#persist_article = persist_article
end
def call(params)
result = validate_article.call(params)
if result.success?
persist_article.call(params)
end
end
end
More specifically, the problematic line is this:
if result.success?
Here's my problem with it: where did the success? method come from? It's not default in Ruby, and result is a local variable, so it should be nearby. But even if it's just omitted in the code sample, where would it have to be defined for that line to work? Everywhere I tried to define it just gave me an 'undefined method' error.
For example, I tried to define it both in the CreateArticle class and in the (only alluded to) ValidateArticle class, the obvious culprits, but no dice.
Update:
The reason I ask is not so much about what success? does as it is because I'm interested in using the pattern in my code. So, for example, my version of the success? method could be just checking whether a value got updated, or an item was inserted into an array. For example, let's say it's just this:
def success? # or self.success?
return true
end
Problem is, I can find no place where I can put this that works. I even created a module just for it and included it into the class, and still it doesn't work (it just returns 'undefined method'). So I'm still at a loss as to where I would have to define such a method so that it would work the way it looks like it should.
It's a method that comes with rails. It checks.for a server response with a 200 code. If it gets a 200 code it returns true else it returns false. Read the rails API docs about it... https://apidock.com/rails/v3.2.3/ActiveResource/Response/success%3F
Actually . success? is a built in ruby method. Check here. What it actually does is checking Stat and returns a boolean.
I did some more digging around the blog and from what I found I suspect that the code is probably making use of the dry-monads gem:
You can explicitly check the type by calling failure? or success? on a monadic value.
It's not explicit in the code excerpt but it's the only thing that makes sense.

How can I temporarily disable PaperTrail when reifying a version?

I am using paper_trail for undo/redo functionality in my site and am having a problem when I call reify.save on a version in that on save and new PaperTrail::Version gets created.
Is there a way to turn off PaperTrail during the saving of a reified object?
I understand that PaperTrail.enabled = false is possible, but I don't want other changes being made a the same time to not be recorded.
My ideal solution would be something along the lines of:
PaperTrail.disable { version.reify.save }
I once accomplished something similar by mixing in something like this:
def without_papertrail
PaperTrail.disable
yield if block_given?
PaperTrail.enable
end
Then you can do something similar to your objective
without_papertrail { version.reify.save }
You can disable paper trail for a particular model, using either of two syntaxes:
m = MyModel.find(123)
m.paper_trail.without_versioning do
# No versioning of `m` happens in this block
end
Note: Since it is called on a model instance, it seems as though this might naturally disable versioning on just that instance, but this syntax disables versioning on the entire model.
The other syntax:
MyModel.paper_trail.disable
# No versioning of MyModel happens here
MyModel.paper_trail.enable
As of today, gem version 10.3.0, the correct way to achieve this is, as per the gem documentation:
PaperTrail.request.disable_model(Banana)
# changes to Banana model do not create versions,
# but eg. changes to Kiwi model do.
PaperTrail.request.enable_model(Banana)
from the readme: https://github.com/paper-trail-gem/paper_trail#7-testing
PaperTrail.enabled = false

Mongoid has_and_belongs_to_many associations

I trying to get mongoid to save associations, but I can only get one side to work. If I have the following test.
test "should add a user as a follower when a user follows the group" do
#cali_group.followers = []
#user1.followed_groups << #cali_group
assert_equal 1, #user1.followed_groups.count
assert_equal 1, #cali_group.followers.count
end
Which is failing, because #cali_group.followers is []. I've been working with this for awhile, tried #cali_group.reload. But it looks like the only way to do this in my code is to work both ends of the join, i.e. #cali_group.followers << #user1. I can do that in my code if I have to.
The models for polco_group and user are here: https://gist.github.com/1195048
Full test code is here: https://gist.github.com/1195052
It can be that:
https://github.com/mongoid/mongoid/issues/1204
Very late to the show. Using Mongoid 4.0.2 here. The issue is troubling me as well.
The link by #sandrew is no longer valid. A similar issue was reported here: http://github.com/mongodb/mongoid/pull/3604
The workaround that I found was:
#cali_group.followers = []
#cali_group.follower_ids # Adding this line somehow does something to the cache
#user1.followed_groups << #cali_group
Found this workaround by adding a before_save in the Group class and observing self.changes. Without this line, the follower_ids member changes from nil to []. However after adding the line, the correct ID of the user is received and set. Hope that helps any future reader.

rails session_store odd behaviour

I am using active_record_store in a rails application which is storing this in session session[:email] = "email#address.com"
now this works fine in the action. but when this action gets over and is redirected to another page, which also accesses the same session[:email] I get an error
undefined method `eq' for nil:NilClass
this should probably mean that i am trying to compare values at some place i am not allowed to. but i cannot see anything like that in the code.
This looks like an old question, but I was just having the same problem and had to figure it out on my own, and thought I would post the solution up here for anyone else that runs into this. It's not very well documented, but to get this to work you have to add:
config.action_dispatch.session_store = :active_record_store
to application.rb, and
Application.config.session_store :active_record_store
to config/initializers/session_store.rb. Then, you have to do:
rake db:sessions:create
and:
rake db:migrate
Then, you have to restart your rails server. I think it was the db:sessions:create step that tripped up the original poster. Not only does that database table have to be laid out the way rails is expecting (that is, with an 'id' column, which is the actual cause of this error, I think), but also the current session has to have a valid ID. Hence the need to create the table and re-start the server, or potentially empty the table if it exists.

Resources