A spelling, expected to be equivalent, causes error. Why? - ruby-on-rails

I'm reading this question, where it says, that the calls
something {|i| i.foo }
something(&:foo)
are equivalent.
Now I was trying to refactor my model named AdminUser according to this pattern and replaced
after_create { |admin| admin.send_reset_password_instructions }
with
after_create(&:send_reset_password_instructions)
, but when I'm running my migration, which contains the lines
def migrate(direction)
super
# Create a default user
AdminUser.create!(email: 'a#b.de', password: 'very_clever', password_confirmation: 'very_clever') if direction == :up
end
it gives me the error
ArgumentError: no receiver given
pointing to the line AdminUser.create!....
Can anyone tell me what goes wrong here?

I know this is an older question, but it interested me quite a bit causing me to do some research of my own. I don't have a corrected code answer for you, but in looking around I believe this post what happened when pass a method to iterator method is very closely related and will most likely answer your question of "what's going wrong here?"
Basically because you're now passing it a proc with the refactored code it's expecting a specific argument that your AdminUser is no longer passing it and causing the error of it not having a receiver.
That being said, I'm sure you have your reasons of setting up your code the way you do, but based on the implied idea of what you're doing and the context I would agree with #photoionized with using
after_create :send_reset_password_instructions as it's clear, concise and (most likely) has your desired outcome.

Related

why am i seeing User::ActiveRecord_Relation instead of ActiveRecord::Relation? [duplicate]

Suppose I have a Rails model: class Project < ActiveRecord::Base
In the Rails console:
> Project.all
=> #<ActiveRecord::Relation []>
That seems reasonable. However,
> Project.all.class
=> Project::ActiveRecord_Relation
What is Project::ActiveRecord_Relation? Specifically,
How did it get "added" (namespaced into) to my model class?
How does it respond to is_a? correctly? Project.all.is_a?(ActiveRecord::Relation) returns true (which is expected), but is Project::ActiveRecord_Relation actually an instance of ActiveRecord::Relation, or is it something else?
Why do this? Why doesn't Project.all return an ActiveRecord::Relation, rather than Project::ActiveRecord_Relation?
(This is in the context of Rails 5.1, in case it's changed in older or newer versions.)
(I'm open to title edits if someone else can come up with a better title for this question)
Check this line of code from ActiveRecord.
https://github.com/rails/rails/blob/f40860800c231ecd1daef6cf6b5a8a8eda76478d/activerecord/lib/active_record/relation/delegation.rb#L23
mangled_name = klass.name.gsub("::", "_")
So, for your questions:
it get's added on activerecord's base when it extendes the delegation module https://github.com/rails/rails/blob/f40860800c231ecd1daef6cf6b5a8a8eda76478d/activerecord/lib/active_record/base.rb#L290
it's actually the same class, just something like an alias (not actually an alias, it's a constant with the class as value)
the class is actually an ActiveRecord::Relation, it's just that the name was changed
There are actually two questions you are asking:
How does it work?
Why is it like that? (What for?)
#arieljuod has already given you some explanations and a link.
However the second question is still unanswered.
There is another similar question exists which I hope will help you find all the answers:
How can an ActiveRecord::Relation object call class methods
It looks like the two questions (by the link and yours one) answer each other )
Take a look at #nikita-shilnikov's answer. Good luck in your investigation!

How do I fix: ArgumentError: invalid byte sequence in UTF-8?

I am getting this type of error in the logs :
Parameters: {"id"=>"4", "step"=>{"documents_attributes"=>{"0"=>
{"file"=>"\x89PNG\r\n\u001A\n\u0000\u0000\u0000\rIHDR\u0000\..."}}}}
def update
#step = Step.find_by(id: params[:id])
if #step.update(steps_params)
render :json => #step
else
render :json => { :responseStatus => 402,
:responseMessage => #step.errors.full_messages.first}
end
end
During update, it rollbacks without giving any error (not execute else condition)
ArgumentError (invalid byte sequence in UTF-8):
(0.2ms) ROLLBACK
How can I fix or handle this type of request?
Your question is how to handle this type of request or error. So here is my suggestion of a general strategy.
First, do your homework. You could easily find this past question, for example. If you have tried the way already but found it did not work, you should have described what you did and what did not work in your question.
Now, I am assuming you can reproduce the case or at least you can expect you will encounter the same problem in near future (or you can wait till then) so you will have a more chance to pin down the problem next time. If you know what parameters caused the error, I guess you can reproduce the case in your development environment. However, if not, it is more tricky to pin down — it heavily depends how much information about the error and input you have and what development environment you can use, and my answer does not cover the case.
The first objective should be to pin down which command (method) exactly in your code caused an error. Did it happen just inside Rails or did your DB raise an error?
In your specific case, did it occur at Step.find_by or #step.update or else? What is steps_params? It seems like a method you have defined. Are you sure steps_params is working as expected? (You may be sure, but we don't know…)
A convenient way to find it out is simply to insert logger.debug (or logger.error) etc before and after each sentence. In doing it, it is recommended to split a sentence into smaller units in some cases. For example, steps_params and update() should be separated, such as (in the simplest case),
logger.debug 'Before steps_params'
res_steps_params = steps_params
logger.debug 'Before update'
res_update = #step.update(res_steps_params)
logger.debug 'Before if'
if res_update
# ……
Obviously you can (and perhaps should) log more detailed information, such as, res_steps_params.inspect, and you may also enclose a part with a begin-rescue clause so that you can get the detailed infromation about the exception and log it. Also, I can recommend to split update into 2 parts – substitutions and save – to find out exactly what action and parameter cause a problem.
Once you have worked out which of DB or Rails or something before (like HTTP-server or Client-browser) is to blame and which parameter causes a problem, then you can proceed to the next stage. The error message suggests it is a character-encoding issue. Is the character encoding of a string invalid (as a UTF-8), or wrongly recognised by Rails (which might be not a fault of Rails but of the client), or not recognised correctly by the DB?
Wherever the problem lies, it is usually (though not always!) possible to fix or circumvent character-encoding problems with Ruby (Rails). The Ruby methods of String#encode, String#encoding, and String#force_encoding would be useful to diagnose and perhaps fix the problem.
As an added note, it can be useful, if possible in your environment, to browse the logfile of your DB (PostgreSQL?) to find out which query passed from Rails to the DB caused a problem (if a query was indeed passed to them!). Alternatively, Rails Gem SQL Query Tracker might be handy to know what queries your Rails app create (though I have never used it and so can't tell much.)
At the end of the day, when a code misbehaves mysteriously, I am afraid only the sure way to solve is to narrow down the problematic clause or parameter step by step. Good luck!

Override to_xml for all objects in Rails 3

Looking to override to_xml method for everything in my app and having a tough time.
The reason is pretty trivial, I need to get rid of the :indent formatting it does by default. I've heard the arguments that "this is a view" problem, and that I should just override to_xml in my models where I need this.
The problem is that I return this stuff programmatically and having :skip_types set makes my responses incorrect. They're incorrect when you have an empty array, and you end up with:
\n
Suddenly it's a string value read by the client cotaining \n (<< there's a bunch of whitespace there, too, but stack overflow doesn't seem to like it). I also don't like the idea of having to override the same thing in 30 places.
That said, the fix is really easy, I just can't seem to put it in the right place. Just looking for help on where to put this. And a second set of eyes on my fix would be appreciated, too.
My fix is
alias __old_to_xml to_xml
def to_xml(options = {})
options.merge!(:indent => 0)
__old_to_xml(options)
end
I generally agree with the apprehension others have about the approach, but I think you could monkey patch it by adding a file to config/initializers with the following:
module ActiveRecord::Serialization
alias __old_to_xml to_xml
def to_xml(opts={})
__old_to_xml opts.merge(:indent => 0)
end
end
If you're on Rails 3, I believe you'll want ActiveModel::Serializers::Xml instead of ActiveRecord::Serialization, but no guarantees.

Rails 3 - How to deal with complicated Switch Statements / If Statements

I'm building a method that ingests incoming email, and processes the email. Along the way there are a lot of things that could prevent the email from being processes successfully. The wrong reply-to address, the wrong from address, an empty message body etc..
The code is full of Switch Statements (case/when/end) and If statements. I'd like to learn a smarter, cleaner way of doing this. Additionally, a way to can track an error and at the end have one location where it emails back the user with an error. Is something like this possible with rails?
#error = []
Case XXX
when xxxx
if XXXXX
else
#error = 'You don't have permission to reply to the xxxxx'
end
else
#error = 'Unfamilar XXXX'
end
Then something at the end like...
If #errors.count > 0
Send the user an email letting them know what went wrong
else
do nothing
end
Thanks for the help here. If you know of any other tutorials that would teach me how to write logic like the above smarter, that'd be great. Right now I have case/if statements going 3 levels deeps, it's hard to keep it straight.
Thanks
First, I would just assign a symbol to each error message as a simple hash:
ErrorsDescription = {
:first => "First error",
:second => "Second error",
...
}
And use symbols instead of strings.
Then, your if and switch statements. Basicaly I can't really help you, because I don't see what kind of condition statements you have. What are you checking? Why do you have 3 level deep conditions? Probably you can write it simpler using if and switch - so this is my first answer to this issue. Another solution may be writing simple methods to improve readability, so you can write like this:
if #email.has_wrong_reply_to_address?
#errors << :wrong_reply_to_address
else
...
end
Also, as #mpapis suggested, you can use Rails build in validation system, but not as ActiveRecord but as ActiveModel. Here you have some examples how to do it and how it works (also take a look here). Of course you may need to write custom validations, but they are just simple methods. Once you do all above job, you can just use:
#email.valid?
And if it is not, you have all errors in hash:
#email.errors
Just as in ordinary ActiveRecord object.
Then you may extend your Emial class with send_error_email method which sends an email if there was an error.
EDIT:
This is about new information you attached in comment.
You don't have to use nested ifs and switch here. You can have it looking like this:
def is_this_email_valid?
if !email_from_user_in_system?
#errors << :user_not_in_system
return false
end
if comment_not_exists?
#errors << :comment_not_exists
return false
end
if user_cannot_comment_here?
#errors << :permision_error
return false
end
...
true
end
Then you can use it:
if !#email.is_this_email_valid?
#email.send_error_mail
end
I suggest using Exceptions. Start with this tutorial, then use Google, trial and error to go from there.
Edit: In more complex cases, exceptions may not be the right tool. You might want to use validator functions instead, for example (see other answers), or you could just return early instead of nesting ifs, e.g.:
unless sender_valid?
#error = "Sender invalid"
return
end
unless subject_valid?
#error = "Invalid command"
return
end
# normal no-errors flow continues here...
You could throw an error when something is not right. Then catch it at the end of your method.
http://phrogz.net/programmingruby/tut_exceptions.html
To make your code more readable and not have a lot of switch and if/then statements, you could create separate methods that validate certain aspects and call them from your main error-checking method.
Is it possible to map your message to a model ? then all the if/switch logic would be validations and automatically handled by rails. Good starting point is active record validations guide
Also worth reading is action mailer guide

Update array in rails action?

I have the following code in an action:
#user = #current_user
#user.votes[1430]='up'
#user.update_attributes(params[:user])
Votes is a string type, there is no default value - I just want to set it for the first time when this action occurs.
Unfortunately I get this error:
NoMethodError
You have a nil object when you didn't expect it!
The error occurred while evaluating nil.votes
any ideas what I'm doing wrong?
The cause of the error seems to be that #user is a nil reference.
You can confirm this by using logging and checking in your console window:
logger.info "user is nil" if #user.nil?
You are assigning #user to be the value of #current_user. I've seen this pattern before and usually current_user is a function, declared elsewhere, not an instance variable. If you are using that pattern, the line should be something like #user = current_user instead.
(Additionally, if votes is a string, your second line appears to be referring to index 1430 of that string, which is probably not what you want either.)
I'm splitting off the comments as I don't want to hijack Evil Trouts response and we seem to be veering away from what was initially spoken about.
Unfortunately I get this error: NoMethodError
You have a nil object when you didn't expect it! The error occurred while evaluating nil.votes
For this, have a look at the authlogic example application. My guess is that you don't have the appropriate before_filter set up and aren't requiring the user to be logged in on that action.
the 1430 is actually two seperate IDs
I don't fully follow this. It's a concatenation of two IDs? What are the IDs for? To be honest, I've never used an array as being a field type in my database so I don't know what the advantages of it are, but whenever I think to myself that an array would be a good idea, I usually question whether or not it wouldn't be better to just have it be a separate model, and hence, table.
It sounds like the situation you are describing might have a Question which a User can vote up on. If so, I might have a separate Voteable model which would join the users with the questions they can vote 'up' on.
Maybe if you provide some more insight into this side of things, I can make a better suggestion. Cheers.

Resources