I posted this issue at the carrierwave-group, but I’m beginning to think this rather is a rails-issue than a problem with carrierwave. The problem’s this:
I have 2 models, ‘article’ and ‘upload’. article has_many :uploads. In my article_controller i have an action named upload:
def upload
@article = Article.find(params[:id])
@article.uploads.create(params[:file])
render :nothing => true
end
this should save a file-upload to article.uploads. I’m using carrierwave to save uploads in the upload-model, but that’s probably not the problem. Before I created the has_many-association I saved the upload directly in the article-model using params[:file] in that exact same action and that worked great.
Now that I created the association there seems to be a problem with params[:file]. I keep getting a NoMethodError:
You have a nil object when you didn't expect it!
You might have expected an instance of Array.
The error occurred while evaluating nil.delete
where line 95 is @article.uploads.create(params[:file])
if I remove the parameter no errors get thrown. But the console tells me params[:file] DOES exists and has proper values. Also params[:file] worked great before I used the has_many association.
I have no clue what the problem could be.
Can anyone give me a hint?
Thanks,
Lukas
params[:file] is not the issue. Its the create method you are calling for @article.uploads that is throwing the error. In your code, you are saying that the create method is part of the upload model, because of your has_many association, so it is looking there. Also, since you are doing a has_many association between article and upload you will receive back an array. If you want to access the method for an object in that array you will need to loop over it or call the object in the array directly.
examples:
Loop over the array
@article.uploads.each {|u| u.create(params[:file])}
Call object in array by position
@article.uploads[0].create(params[:file])
Hmmm, this does work, at least that error doesn’t occur anymore. But now I’m getting the error
Attempt to call private method
where I call create. Also calling create on an instance of an upload doesn’t seem right to (n00by) me. Is that the correct way to add a new instance to the collection associated with has_many? In the rails getting started guide they do it the way I tried it:
(Where :comments is a has_many reference in post) but obviously that didn’t work. I mean am I getting something wrong? What’s the correct way to create and add instances to a has_many association?
So you're probably passing the wrong thing to foo.uploads.create.
Unless you've overridden all sorts of crazy internal active record
stuff, rails is expecting the argument to that create method to be a
hash of attribute names to attribute values, whereas your just giving
it a file.
You have to pass a hash of attribute names to values to create - you
can't just pass a value.
Files are just like any other attribute - you can't for example do
Person.create(params[:name]), you have to do Person.create(:name =>
params[:name]). In the same way you would do foo.uploads.create :file
=> params[:file]
Thanks! One last question though, how would the constructor signature look
for that. Apperently
I wouldn't override the initialiser if I were you. You need to
preserve existing semantics so that (for example) active record can
load your objects from the database. If you really want to, make sure
that you preserve existing calling conventions (ie number of
arguments, pass through the block etc.) and don't forget to call super