Forum: Ruby on Rails has_many << method returns a class with the wrong base type.

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
8f15d89f469605e9e07a8b5ce5d3d5d1?d=identicon&s=25 Sean Wolfe (Guest)
on 2005-12-12 22:04
(Received via mailing list)
I posted this originally on the comp.lang.ruby newsgroup, but I was told
to
bring it here.

I have a layered one to many relationship situation that is having some
weird problems. I've been trying to look for a solution but I can't
seem to find it, or am not certain what keywords I should search on.
Okay lets explain the environment. A Ruby on Rails app, simple CMS.
Just some little tweaks. But versioning needs to be supported, and some
articles require that the body can have multiple pages. Also the
Articles can have multiple types, so they use a Single table
inheritance scheme.
So I have the following classes.
class Article < ActiveRecord::Base
    has_many    :versions


    def new_version(properties = {})
        self.pinned_version += 1
        properties[:version] = self.pinned_version
        self.versions << Version.new(properties)
    end
end

class News < Article
end
# there are other sub classes of articles but for brevity I only
display one for example.

class Version < ActiveRecord::Base
    belongs_to    :article
    has_many    :article_pages
end

class ArticlePage < ActiveRecord::Base
    belongs_to    :version
end

Now in my controller, I have a method that works like this...

# Method to create a new Article. Create's it with the initiated type
# and creates the first version of the Article.
def create
    @article = create_typed_article(params[:article])
    @version = @article.new_version(params[:version])

    params[:article_page].each do |page_name, page_data|
        page = ArticlePage.new()
        page.page_number = page_name.match(/\d+/)[0]
        page.body = page_data
        @version.article_pages << page
    end

    if @article.save
        flash[:notice] = 'Article was successfully created.'
        redirect_to :action => 'list'
    else
        render :action => 'new'
    end
end

Now the problem is, on the line "@version.article_pages << page", I get
the following error:
undefined method `article_pages' for Version:Class

But if I open up the console, and do the following...
v = Version.find(:conditions => ['version = ? AND article_id = ?', 1,
1])
v.article_pages

It works just fine. Now looking more closely at the error, it appears
that the Version object that is returned by new_version inherits from
Class instead of ActiveRecord::Base. Therefore it doesn't seem to have
the collection of ArticlePage objects.

Well, it seems that the problem is that the @version.article_pages <<
method
returns an object with the wrong base type. Other methods from the
collection such as find and the index return an object with the right
base
type.


I guess I can change my method to this:
    def new_version(properties = {})
        self.pinned_version += 1
        properties[:version] = self.pinned_version
        version = Version.new(properties)
        self.versions << version
        version
    end
But that just seems to circumvent some of the niceities of the Ruby
language, and might as well be programming in Java or C#.
Anyone else run into this problem? Is there a solution? Is this a bug,
or by some sort of wicked design?


Thanks,


--
Sean Wolfe
master nerd of
i heart squares, Co.

3711 N. Ravenswood Ave. #147 Chicago, IL 60613
Ph. (773) 531-6301  Fx. (773) 529-7041
http://www.iheartsquares.com
Fe9b2d0628c0943af374b2fe5b320a82?d=identicon&s=25 Eero Saynatkari (rue)
on 2005-12-12 23:07
Sean Wolfe wrote:
> I posted this originally on the comp.lang.ruby newsgroup, but I was told
> to
> bring it here.
>
> I have a layered one to many relationship situation that is having some
> weird problems. I've been trying to look for a solution but I can't
> seem to find it, or am not certain what keywords I should search on.
> Okay lets explain the environment. A Ruby on Rails app, simple CMS.
>
> <snip>
>
> Now in my controller, I have a method that works like this...
>
> <snip>
>
> Now the problem is, on the line "@version.article_pages << page", I get
> the following error:
> undefined method `article_pages' for Version:Class
>
> But if I open up the console, and do the following...
> v = Version.find(:conditions => ['version = ? AND article_id = ?', 1,
> 1])
> v.article_pages
>
> It works just fine. Now looking more closely at the error, it appears
> that the Version object that is returned by new_version inherits from
> Class instead of ActiveRecord::Base. Therefore it doesn't seem to have
> the collection of ArticlePage objects.
>
> Well, it seems that the problem is that the @version.article_pages <<
> method
> returns an object with the wrong base type. Other methods from the
> collection such as find and the index return an object with the right
> base
> type.
>
> <snip>

The problem, by the way, seems to be that 'Version:Class' error,
which indicates that the method called is Version.article_pages,
not Version.new.article_pages as it should.

Some more framework knowledge is required for figuring out why
this is the case.

> Thanks,
> Sean Wolfe


E (from ruby-talk)
8f15d89f469605e9e07a8b5ce5d3d5d1?d=identicon&s=25 Sean Wolfe (Guest)
on 2005-12-13 00:05
(Received via mailing list)
On 12/12/05, Eero Saynatkari <ruby-forum-reg@mailinator.com> wrote:
>
>
> > <snip>
>
> The problem, by the way, seems to be that 'Version:Class' error,
> which indicates that the method called is Version.article_pages,
> not Version.new.article_pages as it should.
>
> Some more framework knowledge is required for figuring out why
> this is the case.


First off, why do you have to be so rude in your answer.

Secondly, your answer is wrong. Actually looking at the return value,
it's
an Array.

Version.new() is called, and creates a new object of type Version.
That object is then added by the Article.article_pages << method. This
method adds the object to the array of Version objects, then it returns
the
actual Article.article_pages objec with the new Version object added to
it.

So actually the correct answer would be on the other end of the
new_version
method I should then grab the last item in the array. Or I can simply
change
my new_version method to:

  def new_version(properties = {})
  self.pinned_version += 1
        properties[:version] = self.pinned_version
        (self.versions << Version.new(properties))[-1]
  end

I just didn't notice the little  "[" before the  returned
"#<Version:0x3804048 ... " when i first was investigating the problem.

It would have been easy to just remind me that my assumption that the <<
method returns the object added instead of the actual object.  But
instead
you deside to act like a know it all, and give me a wrong answer.
Understand
the problem first before making such rude responses publicly.

--
Sean Wolfe
master nerd of
i heart squares, Co.

3711 N. Ravenswood Ave. #147 Chicago, IL 60613
Ph. (773) 531-6301  Fx. (773) 529-7041
http://www.iheartsquares.com
Fe9b2d0628c0943af374b2fe5b320a82?d=identicon&s=25 Eero Saynatkari (rue)
on 2005-12-13 00:33
Sean Wolfe wrote:
> On 12/12/05, Eero Saynatkari <ruby-forum-reg@mailinator.com> wrote:
>>
>>
>> > <snip>
>>
>> The problem, by the way, seems to be that 'Version:Class' error,
>> which indicates that the method called is Version.article_pages,
>> not Version.new.article_pages as it should.
>>
>> Some more framework knowledge is required for figuring out why
>> this is the case.
>
>
> First off, why do you have to be so rude in your answer.

I am sorry if I came across that way; I was trying to explain
what ruby was able to discern and why this might be the right
place instead of ruby-talk.

> Secondly, your answer is wrong. Actually looking at the return value,
> it's
> an Array.

"undefined method `article_pages' for Version:Class" refers to
a situation like (you can test this in irb):

 class Version
 end

 Version.article_pages

It is certainly possible that there are other issues, but
this a strict interpretation of the error. I am not knowledgeable
of any other issues, which is why this forum is probably better
for further inquiries.

> Version.new() is called, and creates a new object of type Version.
> That object is then added by the Article.article_pages << method. This
> method adds the object to the array of Version objects, then it returns
> the
> actual Article.article_pages objec with the new Version object added to
> it.
>
> So actually the correct answer would be on the other end of the
> new_version
> method I should then grab the last item in the array. Or I can simply
> change
> my new_version method to:
>
>   def new_version(properties = {})
>   self.pinned_version += 1
>         properties[:version] = self.pinned_version
>         (self.versions << Version.new(properties))[-1]
>   end
>
> I just didn't notice the little  "[" before the  returned
> "#<Version:0x3804048 ... " when i first was investigating the problem.
>
> It would have been easy to just remind me that my assumption that the <<
> method returns the object added instead of the actual object.  But
> instead
> you deside to act like a know it all, and give me a wrong answer.
> Understand
> the problem first before making such rude responses publicly.

Just attempting to help you based on the information
you provided. Sorry again.

Is the problem solved or is this just a workaround?


> Sean Wolfe

E
8f15d89f469605e9e07a8b5ce5d3d5d1?d=identicon&s=25 Sean Wolfe (Guest)
on 2005-12-13 01:23
(Received via mailing list)
On 12/12/05, Eero Saynatkari <ruby-forum-reg@mailinator.com> wrote:
<snip>
> >
> > First off, why do you have to be so rude in your answer.
>
> I am sorry if I came across that way; I was trying to explain
> what ruby was able to discern and why this might be the right
> place instead of ruby-talk.

Okay, sorry for gunning off there.

> Version.article_pages
Right, but my problem was an assumption of how the << method worked.
The following IRB clued me in:

>> a = Article.new
=> #<Article:0x38130c0 @attributes={"sub_category_id"=>nil,
"last_modified_at"=>
nil, "type"=>"RecordReview", "approved"=>0, "assignment_id"=>nil,
"pinned_versio
n"=>0, "author_id"=>nil, "published_at"=>nil, "read_count"=>0,
"created_at"=>nil
}, @new_record=true>
>> a.versions
=> []
>> v= a.new_version
=> [#<Version:0x3807ca8 @attributes={"rating"=>nil, "artist"=>nil,
"bside_artist
"=>nil, "store_link"=>nil, "abstract"=>nil, "title"=>"",
"release_year"=>nil, "b
est_new_music"=>0, "record_label"=>nil, "version"=>1, "genre"=>nil,
"bside_title
"=>nil, "coverpic_id"=>nil, "article_id"=>0, "image_id"=>nil,
"source"=>nil}, @n
ew_record=true>]
>> v.class
=> Array

Now I could see that v was actually an array containing Version object.
Didn't see those little bracket thingies. After realizing that it was an
Array, I was able to go back and re-read the Array << method description
in
"Programming Ruby". Despite my numerous reads before, I then realized
that I
had a misconception about that method, in which I thought it returned
the
added object, when in reality it returns the whole array with the added
object.

I think I had the result confused with another method but I'm not quite
sure
which at the moment, since all i see as far as return values for most
Array
methods is the Array instance itself, or a new array instance.

> It is certainly possible that there are other issues, but
> this a strict interpretation of the error. I am not knowledgeable
> of any other issues, which is why this forum is probably better
> for further inquiries.

Array does not have the article_pages method. Which would give me the
error
i was having, except I do not understand why it said Version:Class when
the
error should be something like "undefined method `article_pages' for
[]:Array"

Which in the following IRB is exactly what I get:

>>  b = []
=> []
>> b
=> []
>> b.class
=> Array
>> b.something
NoMethodError: undefined method `something' for []:Array
        from (irb):9

<snip>
> Just attempting to help you based on the information
> you provided. Sorry again.
>
> Is the problem solved or is this just a workaround?

Yes, sorry for the little heated exchange. You did help, but I just
misunderstood your tone.

I was able to solve it by changing the new_version method to act how I
wished with as few lines as I was expecting

def new_version(properties = {})
    self.pinned_version += 1
    properties[:version] = self.pinned_version
    (self.versions << Version.new(properties))[-1]
end


--
Sean Wolfe
master nerd of
i heart squares, Co.

3711 N. Ravenswood Ave. #147 Chicago, IL 60613
Ph. (773) 531-6301  Fx. (773) 529-7041
http://www.iheartsquares.com
This topic is locked and can not be replied to.