I have successfully been able to create a user using NanoStoreInMotion. I can query on it and see the object. What I am having an issue with is outputting data. For example:
User model:
class User < NanoStore::Model
:first_name => "Jason"
:last_name => "Beam"
user = User.find(:first_name => "Jason")
#This returns the object [#<User:0xab96ab0>]
end
With ruby, normally to call on a specific field I would just do user.first_name. This throws an error, "undefined method 'first_name' for [#]:Array (NoMethodError)
If I remember correctly find returns an Array so you need to do something like user[0].first_name
Based on my experience I would advise against NanoStoreInMotion. I wouldn't exclude my own inability to use it correctly, but for me it was unreasonably slow (storing thousands of relatively complex objects) and throwing a lot of cryptic errors.
So I moved to MotionModel and I am very happy with it.
Related
I am trying to follow the documentation for Devise Invitable here to send different email for different user types, in my case partners and clients.
So it says to add in your Devise model, which in my case is User.rb, the following code.
....
attr_accessor :invitation_instructions
....
def self.invite_partner!(attributes={}, invited_by=nil)
self.invite!(attributes, invited_by) do |invitable|
invitable.invitation_instructions = :partner_invitation_instructions
end
end
def self.invite_client!(attributes={}, invited_by=nil)
self.invite!(attributes, invited_by) do |invitable|
invitable.invitation_instructions = :client_invitation_instructions
end
end
Then from my controller, when a new user signs up I am calling
....
if current_user.is_client?
user.invite_client!(user, current_user)
else
user.invite_partner!(user, current_user)
end
When I do that the error I get back is
undefined method 'invite_client!' for #<User:0x007ffbcdfabd08>
Which is a little confusing because the method is defined in the user model, so I would think that, at least, it was defined.
Any help on fixing this and getting this setup to work would be greatly appreciated!
I think those are class methods and you should call it like User.invite_client! and also pass your arguments in method.
Same goes for invite_partner!
I have a class that looks something like this:
class OrganicBipedalLifeform < ActiveRecord::Base
# Has the field 'name'
validate :presence_of_name
private
def presence_of_name
errors.add(:base, "name can't be blank") unless name.present?
end
end
And I want the validation error message to use a custom string that excludes (or modifies) the model name, say 'Human/Vulcan name can't be blank'.
If I want this to be the default message for validation errors on this model, is there a better approach than changing the flash details in every view which might display validation errors? Ie by changing something on the model itself?
Apologies if this has been answered elsewhere. I've found a lot of posts about customising the field name, but none about modifying the name of the model itself.
ETA: #TomDunning #Dan, I think I misidentified the source of the problem (or at least didn't make it sufficiently specific), so am creating a new thread to ask what I hope is a better question.
I think you can replace :base with self.class_name or self.class.table_name or a similar class method.
That is bad design, just use this:
validate :name, presence: true
"name can't be blank" would be the default error anyway.
If you then want to extract these later just call my_record.errors or similar.
For a custom error message
validate :name, presence: { message: 'must not be blank' }
Getting around this data store thing that rails provide, I have something that troubles me
Let's say I have a simple post model, with a title, and that for some reason I'd like to store somehow dynamics attributes in another field, call "post_garbage"
In the post model, I have the simple serializer :
class Post < ActiveRecord::Base
serialize :post_garbage
end
As I said, and besides what the rails doc explains, no named accessors are set on this post_garbage field
Playing in the console :
p = Post.first
p.post_garbage["the_stuff"] = "something"
p.save
I get an error, obviously. "the_stuff" is unknown.
Stopping right here, you'd like to dump this data_store thing, safer and easier to create a new field to get the job done (I don't get the utility of it if you have to set an accessor on a data_store field).
* But *
If first an empty hash is saved in this post_garbage field :
p = Post.first
p.post_garbage = {}
p.save
The following becomes possible :
p = Post.first
p.post_garbage["whatever_i_have_in_mind"] = "some value"
p.save
Right after that :
p.post_garbage["it_then_get_dynamic"] = "and that's pretty cool"
p.save
It gets schemaless with no need to specify accessors; kind of provide the expected thing.
So I wonder : many would expect a schemaless thing with the datastore, but it is not said to be used like this by the doc. But it works, with what looks like a bad trick. Wonders…
In the opposite, what's the use of the serialize :post_garbage, if, when empty, it does not returns an empty hash ?
I'd really appreciate some experienced feedback on this one as I feel like I miss something
Thanks a lot
This might have to do with the fact that upon object initialization there is no value in p.post_garbage.
p.post_garbage["the_stuff"] = "something"
Is trying to implicitly treat post_garbage as a hash.
Which would end up being similar to
unset_variable = nil
unset_variable['hash_key'] = 'hash_value'
Using the serialize method for an attribute tells Rails it should expect to condense an Object into a key value map and store it in the database as text. But that doesn't necessarily mean your object is instantiated with this as a hash. It could be any object in particular. But that object needs to be assigned to your attribute before it can be serialized. Serialize may work out the magic to store and reconstitute it on load, but it will not make any assumptions about the form of that object if uninitialized. So without any indication of what object post_garbage is Ruby will not expect it to be a hash.
As for why does it not return an empty has when empty? There is a difference between an empty object and a missing object. (ie: {} vs nil). They are not the same thing, often a missing object is treated like an empty object. But there is value in that distinction, which I expect Rails preserves when loading a serialized attribute.
Perhaps you should try initializing it on create with something like this?
class Post < ActiveRecord::Base
serialize :post_garbage
after_initialize :default_values
private
def default_values
self.post_garbage ||= {}
end
end
Apologies for posting what seems to be an oft-asked question but I have toiled for two days without getting closer.
I am running Rails 4.0.1 (with Devise, CanCan, among others) and have user and role models with a HABTM users_roles table (as created by the since-removed rolify).
class Role < ActiveRecord::Base
has_and_belongs_to_many :users, :join_table => :users_roles
belongs_to :resource, :polymorphic => true
attr_reader :user_tokens
def user_tokens=(ids)
self.user_ids = ids.split(",")
end
end
My submitted form data is:
"role"=>{"name"=>"disabled", "resource_id"=>"", "resource_type"=>"Phone", "user_tokens"=>["", "3"]}
(Not sure where the empty string comes from; it's not in the option list, but hey, welcome to Rails).
My problem is with getting the user_tokens data passed into the appropriate variable in the controller.
There are lots of postings suggesting the correct format (e.g., how to permit an array with strong parameters)
If I specify the permitted parameters thus:
params.require(:role).permit(:name, :resource_id, :resource_type, :user_tokens => [] )
I get a '500 Internal server error' with no other details.
If I specify the permit as
params.require(:role).permit(:name, :resource_id, :resource_type, user_tokens: [] )
I don't get any errors (No unpermitted parameters in the dev log) but the user_tokens array is not passed through in the #role.
If I run this scenario through a console I get:
params = ActionController::Parameters.new(:role => {:resource_id => "", :resource_type => "Phone", :user_tokens => ["", "3"]})
params.require(:role).permit(:name, :resource_id, :resource_type, user_tokens: [] )
=> {"resource_id"=>"", "resource_type"=>"Phone", "user_tokens"=>["", "3"]}
params.require(:role).permit(:user_tokens).permitted?
Unpermitted parameters: resource_id, resource_type, user_tokens
=> true
I'm stuck as to where I should try looking next.
Even though I was sure I had already tried it, changing the model to be
def user_tokens=(ids)
self.user_ids = ids
end
fixed it. I've always struggled to understand this bit of notation except when I've spent 4 days trying why my many:many models don't work.
I guess it'd be easier if I was doing this full time rather than just for particular sysadmin projects.
Having read this:
"No route matches" error?
I'm trying to figure out if there is a gem or way to monkey patch actionpack to get around this constraint.
Basically, I'm writing specs (they run fast), and I don't understand why actionpack throws this error when being applied to an object which isn't "saved".
For two reasons:
Why is it throwing a "No route matches" when it really should be throwing something more meaningful (e.g. object must be saved before a route can be constructed, or object ID is nil). The exception seems a little obscure.
I shouldn't have to save the object at all if all I am trying to do is generate a url for that object, given the ID is populated using a factory or something similar.
This constraint makes it a pain to write fast tests, unless I'm missing something...
True, the error message is a bit obscure. Regarding your second point, you don't need to save an object to generate a URL, the helper will work just as well with a literal value.
building_path(1) # GET /buildings/1 => BuildingsController#show, params={:id=>"1"}
So in the example the object can be replaced with any value:
get :show, :id => "1"
For example, if you use rails generate scaffold Article, RSpec will build a spec like this:
def mock_article(stubs={})
(#mock_article ||= mock_model(Article).as_null_object).tap do |article|
article.stub(stubs) unless stubs.empty?
end
end
describe "GET show" do
it "assigns the requested article as #article" do
Article.stub(:find).with("37") { mock_article }
get :show, :id => "37"
assigns(:article).should be(mock_article)
end
end
which does not hit the database.