SyntaxError on has_many association with block when trying to order

45 views
Skip to first unread message

Antonio Moreno

unread,
Aug 18, 2014, 3:30:12 PM8/18/14
to rubyonra...@googlegroups.com
Hi,

in Ruby on Rails 4, let's say a parent has many children. Then I wanted
to reference only the persisted records in an active record association,
and followed this link's accepted answer
(http://stackoverflow.com/questions/19842765/how-do-you-reference-only-the-persisted-records-in-an-active-record-association).
This works good:

class Parent < ActiveRecord::Base
has_many :children, dependent: :destroy do
def persisted
collect { |a| a if a.persisted? }
end
end

Now, I want to order the associated records:

has_many :children, dependent: :destroy, -> { order 'id asc' } do

but this raises an error:

SyntaxError in ParentsController#index

...trunk/app/models/parent.rb:3: syntax error, unexpected
keyword_do_block, expecting => ...trunk/app/models/parent.rb:49: syntax
error, unexpected keyword_end, expecting end-of-input

However, this does work:

has_many :children, -> { order 'id asc' } do

I can't even find documentation on how to use the do_block on an
association. I'd like to know why it doesn't work what I am trying to
do. Any help appreciated.

--
Posted via http://www.ruby-forum.com/.

Robert Walker

unread,
Aug 18, 2014, 5:21:03 PM8/18/14
to rubyonra...@googlegroups.com
Antonio Moreno wrote in post #1155440:
> Now, I want to order the associated records:
>
> has_many :children, dependent: :destroy, -> { order 'id asc' } do
>
> but this raises an error:
>
> SyntaxError in ParentsController#index

> has_many :children, dependent: :destroy, -> { order 'id asc' } do

This line looks wrong to me. You have a lambda arrow (-> with it's block
{ ... } and immediately trying to open another block with do. Written a
slightly different way it might look something like:

has_many :children, dependent: :destroy, -> do order 'id asc' end do

Here's an example that maybe shows what you're trying to do:

has_many :tracks, -> { order "position" }, dependent: :destroy

In this case it appear to me the lambda function is in the "scope"
argument with options following and no block.

Antonio Moreno

unread,
Aug 19, 2014, 4:26:00 PM8/19/14
to rubyonra...@googlegroups.com
Robert,

thanks for your answer.

>> has_many :children, dependent: :destroy, -> { order 'id asc' } do
>
> This line looks wrong to me. You have a lambda arrow (-> with it's block
> { ... } and immediately trying to open another block with do. Written a
> slightly different way it might look something like:
>
> has_many :children, dependent: :destroy, -> do order 'id asc' end do

It's interesting, because this line:

has_many :children, -> { order 'id asc' } do

works fine (except at destroying associated records, of course), so it
seems it's not a problem with two blocks, right?

> Here's an example that maybe shows what you're trying to do:
>
> has_many :tracks, -> { order "position" }, dependent: :destroy
>
> In this case it appear to me the lambda function is in the "scope"
> argument with options following and no block.

I don't understand what you mean with this, did you miss the "do" at the
end of the line. Anyways, I tried the order I think you are suggesting:

has_many :children, -> { order 'id asc' }, dependent: :destroy do

with no luck. So it seems that I have to choose between having 2 out of
the 3 things I need.

Jason Fleetwood-Boldt

unread,
Aug 19, 2014, 4:47:39 PM8/19/14
to rubyonra...@googlegroups.com
In general if you have a "do" you need an "end", although sometimes ruby interprets the end of your block for you. (but generally it is good practice to always end a "do" with an "end")

Your discrepancy (and confusion) has to do with the way has_many is receiving arguments.

In Rails 4, the second parameter is scope (in rails 3, the second parameter was options)

has_many :children, dependent: :destroy, -> { order 'id asc' } do

you have your arity reversed --- the block you are trying to pass in should come first, followed by the options (this is documented here http://apidock.com/rails/v4.0.2/ActiveRecord/Associations/ClassMethods/has_many)

I don't know why would need or want a "do" statement at the end of that line or anywhere in that line -- it is incorrect, just remove it. 
-- 
You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group.
To unsubscribe from this group and stop receiving emails from it, send an email to rubyonrails-talk+uns...@googlegroups.com.
To post to this group, send email to rubyonra...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/rubyonrails-talk/a5837c82a16e0a31138e8bde53053ded%40ruby-forum.com.
For more options, visit https://groups.google.com/d/optout.


Antonio Moreno

unread,
Aug 19, 2014, 5:20:30 PM8/19/14
to rubyonra...@googlegroups.com
Jason,

thanks for your answer. The link you provided was useful.

> In general if you have a "do" you need an "end",

It does have an end, I left it out of the reply because it is in the
first post. The complete statement I'd like to have would be:

has_many :children, -> { order 'id asc' }, dependent: :destroy do
def persisted
collect { |a| a if a.persisted? }
end
end

What I'm trying to do is briefly mentioned in the page you referenced
(http://apidock.com/rails/ActiveRecord/Associations/ClassMethods/has_many#461-User-a-block-to-extend-your-associations)
but there is no link to further documentation or examples. I just would
need to add the scope to the example, from:

has_many :children, :dependent => :destroy do
def at(time)
proxy_owner.children.find_with_deleted :all, :conditions => [
"created_at <= :time AND (deleted_at > :time OR deleted_at IS
NULL)", { :time => time }
]
end
end

to

has_many :children, -> { order "posted_on" }, :dependent => :destroy do

(rest of the code)

but this is not covered in THAiSi's note. I think this is very useful,
and should be easier to find documentation.

Regards.

Hassan Schroeder

unread,
Aug 19, 2014, 5:25:27 PM8/19/14
to rubyonrails-talk
On Tue, Aug 19, 2014 at 1:25 PM, Antonio Moreno <li...@ruby-forum.com> wrote:

> Anyways, I tried the order I think you are suggesting:
>
> has_many :children, -> { order 'id asc' }, dependent: :destroy do
>
> with no luck.

I believe this (explicitly wrapping the options hash) should work with
your extension:

has_many :children, -> { order 'id asc' }, { dependent: :destroy } do
def persisted
collect { |a| a if a.persisted? }
end
end

Look at the 'Association extensions' section on the has_many doc
page.

--
Hassan Schroeder ------------------------ hassan.s...@gmail.com
http://about.me/hassanschroeder
twitter: @hassan

Antonio Moreno

unread,
Aug 19, 2014, 5:43:28 PM8/19/14
to rubyonra...@googlegroups.com
Hassan,

> I believe this (explicitly wrapping the options hash) should work with
> your extension:
>
> has_many :children, -> { order 'id asc' }, { dependent: :destroy } do

thanks! That did it!

Is it too much to ask why the options hash has to be wrapped?

Regards.

Hassan Schroeder

unread,
Aug 19, 2014, 6:11:19 PM8/19/14
to rubyonrails-talk
On Tue, Aug 19, 2014 at 2:43 PM, Antonio Moreno <li...@ruby-forum.com> wrote:

>> I believe this (explicitly wrapping the options hash) should work with
>> your extension:
>>
>> has_many :children, -> { order 'id asc' }, { dependent: :destroy } do
>
> thanks! That did it!
>
> Is it too much to ask why the options hash has to be wrapped?

Sorry, I'm not a parser internals guy :-)

But when I run into a wtf? syntax error I try to imagine how the line
could be ambiguous to evaluate, and make it as explicit as possible.

Sometimes that's all it takes :-)

Antonio Moreno

unread,
Aug 19, 2014, 6:39:44 PM8/19/14
to rubyonra...@googlegroups.com
>> Is it too much to ask why the options hash has to be wrapped?

I think it might be related to that option hashes can optionally be
"unwrapped" when are the last argument, but must be wrapped otherwise:

http://stackoverflow.com/questions/25194587/syntaxerror-on-has-many-association-with-block-when-trying-to-order

I consider this solved.

Thanks again for your assistance, all of you.
Reply all
Reply to author
Forward
0 new messages