I have a model Team and Division described as a division should have many teams:
class Team < ActiveRecord::Base
belongs_to :division
has_attached_file :logo, :styles => { :large => "120x180>", :thumb => "100x100>", :tiny => "25x25>" },
:url => "/assets/images/:style/teams/#{self.division.name}/:basename.:extension",
:path => ":rails_root/public/assets/images/teams/#{self.division.name}/:basename.:extension"
end
class Division < ActiveRecord::Base
has_many :teams
end
I want to get the name of division of the team by using: #{self.division.name} to include in the string but it doesn't work at all.
Error given:
NoMethodError (undefined method `division' for #<Class:0x007f80179b68f8>):
Even when I use #{self.name} to get the name of the team, but it return only the class name: "Team". In console, I call them just fine:
1.9.3p194 :009 > team = Team.find(4)
Team Load (0.3ms) SELECT `teams`.* FROM `teams` WHERE `teams`.`id` = 4 LIMIT 1
=> #<Team id: 4, name: "Arsenal F.C.", league_id: nil, division_id: 1, stadium_id: 2, history: "This is Arsenal F.C. history file", wins: 1, losses: 1, win_percentage: 1.0, created_at: "2012-08-25 09:25:22", updated_at: "2012-08-27 01:54:08", logo_file_size: 29303, logo_updated_at: "2012-08-27 01:54:08", logo_content_type: "image/png", logo_file_name: "arsenal.png">
1.9.3p194 :010 > team.name
=> "Arsenal F.C."
1.9.3p194 :011 > team.division.name
Division Load (0.3ms) SELECT `divisions`.* FROM `divisions` WHERE `divisions`.`id` = 1 LIMIT 1
=> "English Premier Division"
1.9.3p194 :012 >
I am trying to call self.name (name of the team) or self.division.name (name of the division of the team) in team.rb, not in a controller.
Any idea why? Because of the self hasn't loaded yet? How to solve this?
Update: I really like shioyama's solution because we can pass Proc to paperclip. However, my rails_admin and paperclip and this solution seem still throwing error about gsub on the form. I found another thread Dynamic use of :default_url in Paperclip that will cover my problem. shioyama's solution works fine without rails_admin.
When you use self inside a class definition, it refers to the class itself, not to an instance of that class. To get at the instance you have to use a lambda:
has_attached_file :logo,
:styles => { :large => "120x180>", :thumb => "100x100>", :tiny => "25x25>" },
:url => lamda { |attachment|
team = attachment.instance
"/assets/images/:style/teams/#{team.division.name}/:basename.:extension"
},
:path => lambda { |attachment|
team = attachment.instance
":rails_root/public/assets/images/teams/#{team.division.name}/:basename.:extension"
}
attachment.instance gets the instance that the attachment is attached to (in this case an instance of the Team class). See the paperclip documentation.
See also this answer: can you pass self to lambda in rails?
Related
Is there any way to avoid automatically saving object while assigning collection attributes(collection_singular_ids=ids method)?
for example, I have the following Test and Package model, Package has many tests. User can build package bundle with number of tests.
# test.rb
class Test < ActiveRecord::Base
end
# package.rb
class Package < ActiveRecord::Base
has_many :package_tests
has_many :tests, :through => :package_tests
belongs_to :category
validate :at_most_3_tests
private
# tests count will differ depends on category.
def at_most_3_tests
errors.add(:base, 'This package should have at most three tests') if test_ids.count > 3
end
end
# package_test.rb
class PackageTest < ActiveRecord::Base
belongs_to :package
belongs_to :test
validates_associated :package
end
No issue on validation when package object is new.
1.9.2 :001> package = Package.new(:name => "sample", :cost => 3.3, :test_ids => [1,2,3,4])
=> #<Package id: nil, name: "sample", cost: 3.3>
1.9.2 :002> package.test_ids
=> [1, 2, 3, 4]
1.9.2 :003> package.save
=> false
1.9.2 :004> package.save!
ActiveRecord::RecordInvalid: Validation failed: This package should have at most three tests
1.9.2: 005> package.test_ids = [1,2]
=> [1, 2]
1.9.2 :005> package.save!
=> true
But I couldn't hit at_most_3_tests method with persisted package object.
Join table record is created immediately when assigning test ids
1.9.2: 006> package
=> #<Package id: 1, name: "sample", cost: 3.3>
1.9.2: 007> package.test_ids
=> [1,2]
1.9.2: 007> package.test_ids = [1,2,3,4,5]
=> [1,2,3,4,5]
1.9.2: 008> package.test_ids
=> [1,2,3,4,5]
Client requirement is drop-down interface for selection of multiple tests in package form
and also used select2 jquery plugin for drop-down. Rhmtl code looks like
<%= form_for #package do |f| %>
<%= f.text_field :name %>
<div> <label>Select Tests</label> </div>
<div>
<%= f.select "test_ids", options_for_select(#tests, f.object.test_ids), {}, { "data-validate" => true, :multiple => true} %>
</div>
Please help me to fix this issue.
For limit number of associations
You can use the following validations as the following instead of your method:
has_many :tests, :length => { :maximum => 3 }
For using Multiple select
I have this issue before, and I solved it using the following code:
<%= f.select(:test_ids, options_from_collection_for_select(#tests, :id, :name, #promotion.test_ids), {}, {multiple: true, "data-validate" => true}) =>
I think options_from_collection_for_select, read categories of post example from this link may help you.
For Validation
I used validates_associated, as the following:
validates_associated :tests
For get the old attributes for persisted object
You can use reload for active record as the following:
1.9.2: 006> package
=> #<Package id: 1, name: "sample", cost: 3.3>
1.9.2: 007> package.test_ids
=> [1,2]
1.9.2: 007> package.test_ids = [1,2,3,4,5]
=> [1,2,3,4,5]
1.9.2: 007> package.reload
=> #<Package id: 1, name: "sample", cost: 3.3>
1.9.2: 008> package.test_ids
=> [1,2]
Or you can check validation of package object, if it is false reload it:
unless package.valid?
package.reload
end
If you're manually assigning the test_ids in the controller, I'd suggest updating the entire object with nested attributes instead. This assumes that params[:package][:test_ids] is set to your list of test ids (which Mohamed's answer will help with).
So your controller action would look something like this:
def update
package = Package.find(params[:id])
package.update_attributes params[:package]
end
This will update everything at once in an ActiveRecord/database transaction. This means that if the validation fails, all of the changes will be rolled back, so it won't matter that the tests got saved. More information is here.
Also, I'd recommend calling tests.size instead of test_ids.count, since the replacement will tend to generate a better query (or not have to go to the database at all).
I am able to upload image files as attachments using Attachment_fu but when I try to edit/ modify images which were already uploaded, it does not work.
In my Controller I have this:
def update
#sponsor_account = SponsorAccount.find( params[:id] )
if params[:showcase_category_image_file] &&
!params[:showcase_category_image_file].blank?
#sponsor_account.showcase_category_image =
ShowcaseCategoryImage.new(:uploaded_data =>
params[:showcase_category_image_file])
***This logs - Now the file name is: ***
Rails.logger.info("Now the file name is: #
{#sponsor_account.showcase_category_image.filename}")
end
#sponsor_account.update_attributes( params[:sponsor_account] )
if #sponsor_account.save
flash[:notice] = "Showcase category #{#sponsor_account.name} was updated!"
else
flash[:errors] = #sponsor_account.errors
end
redirect_to sponsor_accounts_path
end
ShowcaseCategoryImage is defined as follows:
has_attachment :content_type => :image,
:storage => :file_system,
:max_size => 5.megabytes,
:thumbnails => { :large => [350, 100], :medium => [200, 90], :thumb =>
[35,35], :preview => [60,60] }
validates_as_attachment
The view has a file_field_tag as follows:
<%= file_field_tag :showcase_category_image_file%>
and my SponsorAccount model says:
has_one :showcase_category_image, :as => :owner, :dependent => :destroy
validates_presence_of :showcase_category_image, :on => :create
Almost similar code works perfectly ok in 'create' but here in 'update' action where there is already a value, this code is not working.
I am getting the below error msgs:
Completed 500 Internal Server Error in 1089ms
ActionView::Template::Error (undefined method `public_filename' for nil:NilClass):
Obviously this error is in the index action where it tries to list all records and their attachments. Since this attachment is empty after the update, this error is thrown in the redirect_to part.
I am using REE1.8.7 and rails 3.2.9
Please help!
This issue was solved when I added :multipart => true in the 'View'. I am using rails 3.2.9 and the rails api has this to say about the 'file_field_tag':
file_field_tag(name, options = {}) Link
Creates a file upload field. If you are using file uploads then you will also need to set the multipart option for the form tag:
Im trying to create an dynamic bucket name depending on my polymorphic association type.
My first approach was trying something like this:
class PostImage < ActiveRecord::Base
belongs_to :imageable, :polymorphic => true
has_attached_file :image, :styles => { :small => "200x200>", :thumb => "50x50>" },
:storage => :s3,
:s3_credentials => "#{Rails.root}/config/s3.yml",
:path => "/:style/:id/:filename",
:bucket => self.imageable_type.to_s
end
If i try to create a new object i got the next error:
NoMethodError: undefined method `imageable_type' for #< Class:0x007fd3fe0b15d8
I find out on the S3 documentation this:
bucket: This is the name of the S3 bucket that will store your files. Remember that the bucket must be unique across all of Amazon S3. If the bucket does not exist Paperclip will attempt to create it. The bucket name will not be interpolated. You can define the bucket as a Proc if you want to determine it's name at runtime. Paperclip will call that Proc with attachment as the only argument.
The problem is that i don't get how i can get this working to set the name of my polymorphic association as the name of the bucket.
Any help will be appreciated.
Hope it help somebody,
The final solution was based on this post: rails paperclip S3 with dynamic bucket name
Read the post for get a better explanation of how use the Proc.
The final code:
class PostImage < ActiveRecord::Base
belongs_to :imageable, :polymorphic => true
has_attached_file :image, :styles => {
:square=> "170x170#",
:rectangle=> "220x170#",
:large => "600x400#" }, :storage => :s3, :s3_credentials => "#{Rails.root}/config/s3.yml",
:path => "/:style/:id/:filename",
:bucket => lambda { |attachment| "#{attachment.instance.imageable_type.to_s.downcase}-gallery" }
end
we are upgrading from rails 2.3 to rails 3 and we have some validation on a model like:
validates_length_of :corporate_type, :in => 1..255, :allow_blank => false, :on => :update, :if => Proc.new { |rra| rra.show_corporate_type? }
In rails 2.3 this only gets called on update, but in rails 3, it seems to be called on create, which breaks some stuff downstream... Can someone explain why this is getting called on create?
Here is the stack:
app/models/rra_agreement.rb:11:in `block in <class:RRAAgreement>'
app/models/foo_application_delegate.rb:29:in `create_application'
Line 28 and 29 are:
rra = RRAAgreement.new()
rra.save
line 11 is the validation line above
thanks
Joel
I would try do the following using :new_record?
validates :corporate_type, :unless => :new_record?
new_records? returns true if it is being just created, else false.
The syntax is changed for rails 3, try this to call only on update,
validates :corporate_type,:length => {:on => :update, :min => 1, :max => 20 }
Well I have a work around, its ugly, but it seems to at least let us move forward:
validates_length_of :corporate_type, :in => 1..255, :allow_blank => false, :on => :update, :if => Proc.new { |rra| return false if rra.id==nil;rra.show_corporate_type? }
This makes it just false if the id is not there,it should be there on update.
I am using paperclip to upload photos in my two rails app which share a single database. Now the problem is, if I upload a photo in app-a, for instance, paperclip gives me a url as:
http://s3.amazonaws.com/testing-item-photos-akiajbfjoiwfjzd6aypa/Users/yujunwu/app-a/public/item_19/created_at_2012-09-29%2021:52:02%20UTC/large.jpg?1348955522
Here is what I set up in my item model:
class Item < ActiveRecord::Base
attr_accessible :photo, :photo_url, :poll_id, :brand, :number_of_votes
has_attached_file :photo,
:styles => { :thumbnail => "100x100#",
:small => "150x150>",
:medium => "250x250>",
:large => "400x400>" },
:storage => :s3,
:s3_credentials => S3_CREDENTIALS,
:url=>"/item_:id/created_at_:created_at/:style.jpg"
Paperclip.interpolates :created_at do |attachment, style|
attachment.instance.created_at
end
end
In the other app app-b, when I query the url with item.photo.url(:large), it gave me:
http://s3.amazonaws.com/testing-item-photos-akiajbfjoiwfjzd6aypa/Users/yujunwu/app-b/public/item_19/created_at_2012-09-29%2021:52:02%20UTC/large.jpg?1348955522
Therefore I got a wrong url.
Are there any ways I can do that by configuring paperclip? Thanks!
As described here : https://github.com/thoughtbot/paperclip#defaults , you can change the default config, in your case I guess you want to change the :local_root so it doesn't include the app name.