RoR one-to-many association show view - ruby-on-rails

In my first Ruby on Rails app I've a one-to-many association
class Battle < ActiveRecord::Base
has_many :rivals, :dependent => :destroy
accepts_nested_attributes_for :rivals, :allow_destroy => true
attr_accessible :question, :rivals_attributes
end
class Rival < ActiveRecord::Base
belongs_to :battle
has_attached_file :rival_image, :styles => { :normal => "300x300>", :thumb => "100x100>" }
end
Let's say a battle has 2 rivals
<% for rival in #battle.rivals %> <%= rival.name %> <% end %> displays both rivals that belongs to battle
How do I display first rival and the second one where I need it?

If you want to access individual records from a association use:
<%= battle.rivals[0].name %>

Related

RoR - Searching gem for uploading files

I'm searching a gem (like paperclip or carrierwave) that allows you to upload images. But I want a relationship between the image and the otherside:
I have a table day
And I want a own table for the images so that at the and I'm going to have an has_many belongs_to relationship.
So one day has many images
any suggestions?
If I understand you correctly, you may want to look at the has_many :through relationship for this. We have this working with Paperclip & allows you to have many images to one record:
#app/models/day.rb
Class Day > ActiveRecord::Base
has_many :day_images, :class_name => "DayImage"
has_many :images, :class_name => "Image", :through => :day_images, dependent: :destroy
accepts_nested_attributes_for :day_images, :allow_destroy => true
end
#app/models/day_image.rb
Class DayImage > ActiveRecord::Base
belongs_to :day, :class_name => "Day"
belongs_to :image, :class_name => "Image"
accepts_nested_attributes_for :image, :allow_destroy => true
end
#app/models/image.rb
Class Image > ActiveRecord::Base
has_many :day_images, :class_name => "DayImage"
has_many :days, :class_name => "Day", :through => :day_images, dependent: :destroy
end
The join model would then look like this:
day_images table
id | day_id | image_id | extra attribute | extra attribute | created_at | updated_at
This would allow you to allocate images to the day model using the accepts_nested_attributes_for, like this:
Nested Models
Nested models are pretty tough to get right at first, but get easier the more you do them
Using the models I outlined above, you'll have to add several important factors to make accepts_nested_attributes_for work for you. Here's how:
#app/controllers/days_controller.rb
def new
#day = Day.new
#day.day_images.build.build_image
end
def create
#day = Day.new(day_params)
#day.save
end
private
def day_params
params.require(:day).permit(:day, :variables, day_images_attributes: [:image_id, :extra_attributes, :in, :join, :model, image_attributes: [:image]])
end
This will allow you to create a form like this:
#app/views/days/new.html.erb
<%= form_for #day do |f| %>
<%= f.text_field :day_attribute %>
<%= f.fields_for :day_images do |day_image| %>
<%= day_image.text_field :caption %>
<%= day_image.collection_select(:image_id, Image.where(:user_id => current_user.id), :id, :image_name, include_blank: 'Images') %> --> this will allow you to assign images
<%= day_image.fields_for :image do |i| %>
<%= i.file_field :image %> --> uploads new image
<% end %>
<% end %>
<% end %>
This is all based off live code. If you need any more help, let me know!

Issue occurs due to "accepts_nested_attributes_for" and "has_many through" relationship which gives not id found error with factory_girl and rspec

Following are models:
class User < ActiveRecord::Base
has_many :companies_users
has_many :companies, :through => :companies_users
end
class Company < ActiveRecord::Base
has_many :companies_users
has_many :users, :through => :companies_users
accepts_nested_attributes_for :users
attr_accessible :name, :address_1, :address_2, :area, :city, :state, :zipcode, :country, :users_attributes
after_create :create_subscriptions
def create_subscriptions
subscription=Subscription.create(:company_id => self.id, :subscription_dt => Date.today, :is_active => 'Y', :user_id => self.users.first.id)
subscription.save
end
end
class CompaniesUser < ActiveRecord::Base
belongs_to :user
belongs_to :company
end
Following are spec/factories/factory.rb
FactoryGirl.define do
factory :company do |f|
f.name "TestCompany"
f.domain_url "test_url"
users {|t| [t.association(:user)] }
end
factory :user do |f|
f.first_name "John"
f.last_name "Doe"
f.password "password"
f.email "JohnDoe#test.com"
f.mobile_no "25589875"
f.fax_no "25548789"
f.office_no "25578455"
end
factory :companiesuser do |f|
association :user
association :company
end
end
Following is my spec/model/company_spec.rb
context "Check methods" do
it "check after create methods" do
company = FactoryGirl.create(:company)
end
end
While executing above company_spec it creates an issue due to method subscription which exist in company model and call after create callback create_subscriptions.which require self.users.first.id which it did not get and provide me following error.
$ rspec spec/models/company_spec.rb
F
Failures:
1) Company Model: Check methods check after create methods
Failure/Error: company = FactoryGirl.create(:company)
RuntimeError:
Called id for nil, which would mistakenly be 4 -- if you really wanted the id of nil, use object_id
# ./app/models/company.rb:47:in `create_subscriptions'
# ./spec/models/company_spec.rb:45:in `block (3 levels) in <top (required)>'
Can anyone let me know what i need to do or its any association related issue? it create problem because first it enter values in company but not able to enter value in users table so not get user id which required in subscription method.
I resolved above issue by change code in "spec/model/company_spec.rb" as follow:
context "Check methods" do
it "check after create methods" do
company = create(:company,"name"=>"mycom","domain_url"=>"test","users_attributes"=>{"0"=>{"email"=>"test#testing.com","password"=>"password","password_confirmation"=>"password"}})
end
end
It created data in my join table also and worked successfully. Obviously its not done by factory join. I directly pass the user attributes here. So removed line
users {|t| [t.association(:user)] }
from company's factory.
I've done a nested has_many :through and you have to basically pass the attributes to the :companies_users model and then to the :users model
My Code (Rails 4.0)
Form
#views/admin/posts/new
<%= form_for [:admin, resource], :html => { :multipart => true } do |f| %>
<table class="resource_table">
<thead>
<th colspan="2"><%= params[:action].capitalize %> <%= resource_class %></th>
</thead>
<tbody class="form">
<% attributes.each do |attr| %>
<tr class="<%= cycle('odd', '')%>">
<td><%= resource_class.human_attribute_name(attr) %></td>
<td>
<% if attr == "body" %>
<%= f.text_area attr, :rows => 60, :cols => 80, :class => "redactor" %>
<% else %>
<%= f.text_field attr, :value => resource.public_send(attr).to_s %>
<% end %>
</td>
</tr>
<% end %>
<%= f.fields_for :images_posts do |images_posts| %>
<%= images_posts.fields_for :image do |images| %>
<tr>
<td>Image</td>
<td><%= images.file_field :image %></td>
</tr>
<% end %>
<tr>
<td>Caption</td>
<td><%= images_posts.text_field :caption %></td>
</tr>
<% end %>
<tr class="dull">
<td colspan="2"><%= f.submit "Go" %></td>
</tr>
</tbody>
</table>
<% end %>
Models
#models/image_post.rb (the join model)
class ImagePost < ActiveRecord::Base
#Associations
belongs_to :post, :class_name => 'Post'
belongs_to :image, :class_name => 'Image'
#Validations
validates_uniqueness_of :post_id, :scope => :image_id
#Nested Association (Can upload & add images from form)
accepts_nested_attributes_for :image, :allow_destroy => true
end
#models/image.rb
class Image < ActiveRecord::Base
#Associations
has_many :products, :class_name => 'Product', :through => :images_products, dependent: :destroy
has_many :images_products, :class_name => 'ImageProduct'
has_many :posts, :class_name => 'Post', :through => :images_posts, dependent: :destroy
has_many :images_posts, :class_name => 'ImagePost'
has_many :brands, :class_name => 'Brand', :through => :brands_images, dependent: :destroy
has_many :brands_images, :class_name => 'BrandImages'
#Image Upload
Paperclip.options[:command_path] = 'C:\RailsInstaller\ImageMagick'
has_attached_file :image,
:styles => { :medium => "x300", :thumb => "x100" },
:default_url => "",
:storage => :s3,
:bucket => ''
:s3_credentials => S3_CREDENTIALS
#Validations
validates_presence_of :image, :message => "No Image Present!"
end
#models/post.rb
class Post < ActiveRecord::Base
#Images
has_many :images, -> { uniq }, :class_name => 'Image', :through => :images_posts, dependent: :destroy
has_many :images_posts, :class_name => 'ImagePost'
#Nested Association (Can upload & add images from form)
accepts_nested_attributes_for :images_posts, :allow_destroy => true
end
This was a BIG help for me: Rails nested form with has_many :through, how to edit attributes of join model?
Diagnosing Your Issue
I posted my code to give you a working example of what you can do (mine still needs refinement, but it works)
Looking at your code, you should add "accepts_nested_attributes_for" into your companies_users.rb model like this:
accepts_nested_attributes_for :user
In your companies model, change your accepts_nested_attributes_for to:
accepts_nested_attributes_for :companies_users

rails 3 polymorphic association with paperclip and multiple models

I want to make polymorphic associations with paperclip, and allow my user to have one avatar and multiple images.
Attachment model:
class Attachment < ActiveRecord::Base
belongs_to :attachable, :polymorphic => true
end
class Avatar < Attachment
has_attached_file :image, :styles => { :thumb => "150x150>", :view => "260x180>" },
end
class Image < Attachment
has_attached_file :image, :styles => { :thumb => "150x150>", :view => "260x180>" },
end
User Model:
has_one :avatar, :as => :attachable, :class_name => 'Attachment', :conditions => {:type => 'avatar'}
accepts_nested_attributes_for :avatar
User Controller:
def edit
#user.build_avatar
end
User View form:
<%= form_for #user, :html => { :multipart => true } do |f| %>
<%= f.fields_for :avatar do |asset| %>
<% if asset.object.new_record? %>
<%= asset.file_field :image %>
<% end %>
<% end %>
when I attempt to save the changes I get the error => unknown attribute: avatar
if I remove the :class_name => 'attachment' in the has_one association I get the error =>
uninitialized constant User::Avatar
I need to also attach avatars to blog posts, so I need the association to be polymorphic (or atleast i think so)
I am stumped and any help would be greatly appreciated.
I do have a project in the works that is successfully using Paperclip and polymorphic associations. Let me show you what I have, and maybe you can apply it to your project:
class Song < ActiveRecord::Base
...
has_one :artwork, :as => :artable, :dependent => :destroy
accepts_nested_attributes_for :artwork
...
end
class Album < ActiveRecord::Base
...
has_one :artwork, :as => :artable, :dependent => :destroy
accepts_nested_attributes_for :artwork
...
end
class Artwork < ActiveRecord::Base
belongs_to :artable, :polymorphic => true
attr_accessible :artwork_content_type, :artwork_file_name, :artwork_file_size, :artwork
# Paperclip
has_attached_file :artwork,
:styles => {
:small => "100",
:full => "400"
}
validates_attachment_content_type :artwork, :content_type => 'image/jpeg'
end
the songs form and the albums form include this as a partial:
<div class="field">
<%= f.fields_for :artwork do |artwork_fields| %>
<%= artwork_fields.label :artwork %><br />
<%= artwork_fields.file_field :artwork %>
<% end %>
don't forget to include :html => { :multipart => true } with the form
artworks_controller.rb
class ArtworksController < ApplicationController
def create
#artwork = Artwork.new(params[:artwork])
if #artwork.save
redirect_to #artwork.artable, notice: 'Artwork was successfully created.'
else
redirect_to #artwork.artable, notice: 'An error ocurred.'
end
end
end
and finally, an excerpt from songs_controller.rb:
def new
#song = Song.new
#song.build_artwork
end
I'm not sure you really need to be polymorphic. How about this approach, which uses has_many :through? In plain English, the user has one avatar which has multiple images, and through this association you can call User.images to get the collection of images associated with the avatar.
http://guides.rubyonrails.org/association_basics.html
class User < ActiveRecord::Base
has_one :avatar
has_many :images, :through => :avatar
end
class Avatar < ActiveRecord::Base
belongs_to :user
has_many :images
end
class Image < ActiveRecord::Base
belongs_to :avatar
has_attached_file :image, :styles => { :thumb => "150x150>", :view => "260x180>" },
end
Having said all of this, I am left to wonder why you need to go through all this anyway. Why not just do
class User < ActiveRecord::Base
has_many :avatars
end
which would give you as many images (avatars) as you want.

Rails 3 - Using tags to associate photos with polymorphic Taggable class

My goal is to create a system for associating photos with objects from any of several classes (Events, Organizations, Developments) using Tags. For the life of me, I can't get this to work out, despite the fact that it seems like a pretty common situation.
I'm relatively new to anything but the most basic Rails development, so I'm having a hard time forming the question. Please excuse any misnomers.
Tag model:
class Tag < ActiveRecord::Base
attr_accessible :photo_id, :taggable_id, :taggable_type
belongs_to :photo
belongs_to :taggable, :polymorphic => true
end
Photo model:
class Photo < ActiveRecord::Base
attr_accessible :tags_attributes
has_many :tags, :dependent => :destroy
accepts_nested_attributes_for :tags, :reject_if => lambda { |a| a[:taggable_id].blank? }
end
Event model:
class Event < ActiveRecord::Base
has_many :tags, :as => :taggable, :dependent => :destroy
end
Organization model:
class Organization < ActiveRecord::Base
has_many :tags, :as => :taggable, :dependent => :destroy
end
Development model:
class Development < ActiveRecord::Base
has_many :tags, :as => :taggable, :dependent => :destroy
end
In my Photo fields, I'm trying to use the nested_form gem to add tags to the photo (so I can later call those tagged objects in the photo's views, and the photo in the tagged object's views).
photos/new.html.erb (I have included the nested_form javascript)
<% nested_form_for #photo, :html => { :multipart => true } do |f| %>
...
<%= f.fields_for :tags do |tag_form| %>
<%= tag_form.collection_select :taggable_id, Taggable.all, :id, :name %>
<%= tag_form.link_to_remove "remove" %>
<% end %>
<p><%= f.link_to_add "Add tag", :tags %></p>
...
<% f.submit "Add photo" %>
<% end %>
Is the structure of my models suitable for what I'm trying to do?
and, if so,
How can I properly specify both he :taggable_id and :taggable_type in my nested form?
Thanks in advance for any guidance!
You need to make your Photo model polymorphic and use something like attachment_fu / paperclip to upload photos.
class Photo < ActiveRecord::Base
has_attachment :content_type => :image,
:storage => :file_system,
:max_size => 2000.kilobytes,
:resize_to => '500x500>',
:thumbnails => { :thumb => '215x215>'}
validates_as_attachment
belongs_to :attachable, :polymorphic => true
end
class Event < ActiveRecord::Base
has_many :tags, :as => :taggable, :dependent => :destroy
has_many :attachments, :as => :attachable
end
class Organization < ActiveRecord::Base
has_many :tags, :as => :taggable, :dependent => :destroy
has_many :attachments, :as => :attachable
end
class Development < ActiveRecord::Base
has_many :tags, :as => :taggable, :dependent => :destroy
has_many :attachments, :as => :attachable
end
Your photos table should have attachable_id and attachable_type columns. With this you should be able to add photos to different object all stored in polymorphic photo model. Tagging also uses polymorphic associations and works in similar way. the documentation for the plugin would help. Hope that works for you.

Nested attributes problems - paperclip

3 models
class Country < ActiveRecord::Base
has_many :regions
has_many :assets, :dependent => :destroy
accepts_nested_attributes_for :assets
end
class Region < ActiveRecord::Base
belongs_to :country
has_many :appartments
has_many :assets, :dependent => :destroy
accepts_nested_attributes_for :assets
end
class Asset < ActiveRecord::Base
belongs_to :region
belongs_to :country
has_attached_file :image,
:styles => {
:thumb=> "100x100>",
:small => "300x300>",
:large => "600x600>"
}
end
The edit form
<%= f.fields_for :assets do |asset| %>
<% if asset.object.new_record? %>
<%= asset.file_field :image %>
<% end %>
<% end %>
My region controller:
def edit
#country = Country.find(params[:country_id])
# For URL like /countries/1/regions/2/edit
#region = #country.regions.find(params[:id])
5.times { #country.region.assets.build }
end
I get
"undefined method `region' for #<Country:0x007fbf8b848198>"
Someone ideas?
5.times { #country.region.assets.build }
should be
5.times { #region.assets.build }

Resources