I am currently working on a web application where a contractor (electrician, roofer, plumber) etc can make a proposal online. Pictures, youtube videos of the project, and a text description will be provided to the contractor from the customer.
So far I am working on the pictures feature using carrierwave
This is the table of this model in my schema
create_table "project_pictures", force: true do |t|
t.string "name"
t.string "picture"
t.datetime "created_at"
t.datetime "updated_at"
end
Here are my two records in my rails console
ProjectPicture Load (0.4ms) SELECT "project_pictures".* FROM "project_pictures"
=> #<ActiveRecord::Relation [#<ProjectPicture id: 2, name: "Request for Siding Quote Customer A", picture: "siding.jpg", created_at: "2013-08-15 16:10:22", updated_at: "2013-08-15 16:47:02">, #<ProjectPicture id: 1, name: "Request for Siding Quote Customer A", picture: "sidingrequest.jpg", created_at: "2013-08-14 01:54:27", updated_at: "2013-08-15 16:47:39">]>
The thing is I am trying to link multiple pictures to one customer. Lets say the above two pictures belong to one customer and there are two rows because there are two pictures.
How do I reference that in the table, lets say I have one customer and thats me "judy"
both the record should reference judy's id?
and then eventually in the view, I can draw both pictures out using an image tag that belong to the customer id 1 - with name = "judy" or just customer id = 1?
If I am not making things clear please let me know, I am not that familiar with tables relationships and which relationship will help me the most.
create table :projects do |t|
t.references :clients
t.timestamps
end
create_table :pictures do |t|
t.string :name, null:false
t.string :location, null:false
t.references :projects, null:false
t.timestamps
end
... meanwhile.. back in the model layer
class Project < ActiveRecord::Model
has_many :pictures, :dependent => destroy
end
class Picture < ActiveRecord::Model
belongs_to :project
validates_presence_of :project
end
To get all Judy's pictures
Client.where("name like ?", "Judy").projects.first.pictures
I would have set it up like this
user has_many project_pictures
project_pictures belongs_to user
your project picture table should have a row for the user_id.
Related
This will be fairly quick and easy for most of you...I have a table called types, and another called projects. A project can only have one type, but a type can have many projects. For instance a community garden project and a playground project can both have the type of 'greenspace'. So I have set up a has_many association. In my types model I have this:
has_many :projects
and in my projects model I don't have anything (I previously had has_one in it but upon looking at the docs it seemed incorrect). In the projects#show view I would like the name of the type to display. The parks project's view should say 'greenspace'. but I am getting the error
undefined method `type' for #<Project:0x007ffdd14fcde8>
I am trying to access that name using:
<h3>Type: <%= #project.type.project_type %> </h3>
i have also tried:
<h3>Type: <%= #project.type_id.project_type %> </h3>
but of course type_id gives a number, and there is no project_type for a number. project_type being the name of the column which holds the string data 'greenspace'. Am I accessing it wrong? Or have I set it up incorrectly?
Also in my schema, projects looks like this:
create_table "projects", force: :cascade do |t|
t.string "type_id"
t.text "description"
t.integer "money_needed"
t.integer "money_raised"
t.float "interest_offered"
t.datetime "end_date"
t.integer "user_id"
t.datetime "created_at"
t.datetime "updated_at"
t.string "name"
t.text "url"
end
Project can belong_to both. Like this
#app/models/project.rb
class Project < ActiveRecord::Base
belongs_to :type
belongs_to :user
#...
end
#app/models/user.rb
class User < ActiveRecord::Base
has_many :projects
#...
end
#app/models/type.rb
class Type < ActiveRecord::Base
has_many :projects
#...
end
In the Project model you should state:
belongs_to => :type
In general, for most associations there is going to be an inverse. Not always, as you might have multiple associations in Type for Project. For example as well as your current has_many :projects, you might have others to return only projects that are unfinished, and such an association would not need an inverse.
Bear in mind that when you state: #project.type Rails is going to look for a method on #project. The association is what provides this method, and effectively the result is then the Type object that is referenced by the Project. It's important to realise that #project.type only returns a Type because the association tells it to -- the magic does not extent to just inferring that that is what is wanted.
I have a VideoCollection model that will contain many records from another model (called VideoWork), using the has_many relationship. The VideoCollection model inherits from the Collection model using single table inheritance, while the VideoWork model inherits from the Work model.
I'm having a problem when I try to call up the video_works that belong to a video_collection.
In my video_collection#show action, I use the following to try to display a collection's works:
def show
#video_collection = VideoCollection.find(params[:id])
#collections = #video_collection.children
#works = #video_collection.video_works
end
But when I try to use #works in the show view, I get the following:
PG::Error: ERROR: column works.video_collection_id does not exist
SELECT "works".* FROM "works" WHERE "works"."type" IN ('VideoWork') AND "works"."video_collection_id" = $1
##(Error occurs in the line that contains <% #works.each do |work| %>)
My model files:
#----app/models/video_collection.rb----
class VideoCollection < Collection
has_many :video_works
end
#----app/models/video_work.rb----
class VideoWork < Work
belongs_to :folder, class_name: "VideoCollection", foreign_key: "folder_id"
end
The "parent" models:
#----app/models/collection.rb - (VideoCollection inherits from this)
class Collection < ActiveRecord::Base
end
#----app/models/work.rb - (VideoWork inherits from this)
class Work < ActiveRecord::Base
end
The Schema file:
#----db/schema.rb----
create_table "works", force: true do |t|
t.string "header"
t.string "description"
t.string "type"
t.string "folder_id"
end
create_table "collections", force: true do |t|
t.string "type"
t.datetime "created_at"
t.datetime "updated_at"
t.text "ancestry"
t.string "name"
t.string "tile_image_link"
end
My Question
I assume that since I have a folder_id column in the works table that I should be able to set up the belongs_to relationship properly, but it seems that Rails still wants me to have a video_collection_id column instead. I would prefer not use something specific like video_collection_id as a foreign key in the works table since I need to set up other relationships (e.g.: photo_collection has_many photo_works, etc).
What am I doing wrong here?
I don't really use has_many and belongs_to with different foreign keys than the standard, but according to the docs I would do this:
class VideoCollection < Collection
has_many :video_works, foreign_key: "folder_id"
end
class VideoWork < Work
belongs_to :folder, class_name: "VideoCollection", foreign_key: "folder_id"
end
Your Pg error says that the association is looking for 'video_collection_id' instead of 'folder_id'
Guides (chapter 4.3.2.5)
In my Rails app, I only require users to enter email and name upon signup, but then give them the option to provide fuller contact details for their profile. Therefore, I have a User.rb model that has an association with Contact.rb, namely,
User.rb
has_one :contact
Contact.rb
belongs_to :user
Contact.rb has the predictable fields you might expect such as address, postal code etc, but it also stores the province_id for a relation with the Province.rb model, so
Contact.rb
attr_accessible :address, :city, :mobile, :postalcode, :province_id, :user_id
belongs_to :user
belongs_to :province
Province.rb
has_many :contacts
I did it that way (rather than storing the name of the province as a "string" on contact.rb) so that I could more easily (so I thought) categorize users by province.
In the show action of one of the artists_controller, I do the following to check whether the user is trying to sort by province and then call an artists_by_province method that does a search
if params[:province_id]
province = params[:province_id]
province = province.to_i #convert string to integer
#artistsbyprovince = User.artists_by_province(province)
else
#artists = User.where(:sculptor => true)
end
This is the method on the User.rb model that it calls if a province id is passed in
scope :artists_by_province, lambda {|province|
joins(:contact).
where( contact: {province_id: province},
users: {sculptor: true})
}
However it gives me this error:
Could not find table 'contact'
If I make contacts plural
scope :artists_by_province, lambda {|province|
joins(:contacts).
where( contacts: {province_id: province},
users: {sculptor: true})
}
This error
Association named 'contacts' was not found; perhaps you misspelled it?
Can anyone tell me what I'm doing wrong when I'm making this query?
Update: I changed some of the details after posting because my copy and paste had some problems with it
P.S. ignore the fact that I'm searching for a 'sculptor.' I changed the names of the user types for the question.
from schema.rb
create_table "contacts", :force => true do |t|
t.string "firm"
t.string "address"
t.string "city"
t.string "postalcode"
t.string "mobile"
t.string "office"
t.integer "user_id"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
t.integer "province_id"
end
The problem was fixed by using contact (singular) in the join and contacts (plural) in the where clause. I'm guessing 'contact' (singular) reflects the has_one association between User.rb and Contact.rb, whereas 'contacts' is used in the where clause to represent the name of the table, which is always plural.
User.rb
has_one :contact
scope :artists_by_province, lambda {|province|
joins(:contact).
where( contacts: {province_id: province},
users: {sculptor: true})
}
Can you try the following?
scope :artists_by_province, lambda {|province|
joins(contact: {province: { id: province}}).
where(sculptor: true)
}
UPDATE (specific and more detailed previous version is below):
I'm developing a TV station web site. Here are requirements for my Program section:
Each Program has ONE Category.
Each Program has ONE Subcategory.
Each Category has MANY Subcategories
Each Category has MANY Programs.
Each Subcategory has ONE Category
Each Subcategory has MANY Programs.
I want to retrieve all these three models to be associated. For example, I should be able to retrieve below data from my views:
While:
p = Program.find(1)
p_cat = ProgramCategory.find(1)
p_subcat = ProgramSubcategory.find(1)
I should be able to retrieve and also EDIT these:
p.program_category
p.program_subcategory
or
program_category.programs
program_subcategory.programs
You can see what I tried below to achieve these requirements. You may recommend me a totally different way or fix my mistakes.
Thank you
============================================================
I have 3 models. They are supposed to be nested in eachother.
ProgramCategory > ProgramSubcategory > Program
Here are my codes:
ProgramCategory model:
has_many :programs
has_many :program_subcategories
ProgramSubcategory model:
belongs_to :program_category
has_many :programs
Program Model:
belongs_to :program_category
belongs_to :program_subcategory
As I create a new Program, I can set its Category and everything is fine. I can access them from both sides. For example,
program.program_category
gives me what I expected. and also
program_category.programs
gives me what I want to have, too.
BUT, -here comes the question-
When I try to access program.program_subcategory, I receive just a nil.
Eventhough my Subcategory's Category is set and my Program's Category is set too, why I can't access program.program_subcategory directly?
When I type program_category.program_subcategories, I receive all Subcategories owned by that Category. But I CAN NOT get Subcategories from directly a Program object.
My scheme is below. Any help is appriciated.
ActiveRecord::Schema.define(:version => 20120926181819) do
create_table "program_categories", :force => true do |t|
t.string "title"
t.text "content"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
create_table "program_subcategories", :force => true do |t|
t.integer "program_category_id"
t.string "title"
t.text "content"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
add_index "program_subcategories", ["program_category_id"], :name => "index_program_subcategories_on_program_category_id"
create_table "programs", :force => true do |t|
t.integer "program_category_id"
t.integer "program_subcategory_id"
t.string "title"
t.text "content"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
add_index "programs", ["program_category_id", "program_subcategory_id"], :name => "my_join1", :unique => true
end
The design is strange a bit. If you need nesting like
ProgramCategory > ProgramSubcategory > Program
then you need
class Program < ActiveRecord::Base
belongs_to :program_subcategory
end
class ProgramSubcategory < ActiveRecord::Base
belongs_to :program_category
has_many :programs
end
class ProgramCategory < ActiveRecord::Base
has_many :programs, :through => :program_subcategories
has_many :program_subcategories
end
This way when you create a program you can assign a subcategory to it. And this subcategory is already assigned to category, so you can access it via program.program_subcategory.program_category
And you do not need program_category_id foreign key in programs because program is not connected to category directly, but via subcategory.
UPDATE
Each Program has ONE Category.
Each Program has ONE Subcategory.
Each Category has MANY Subcategories
Each Category has MANY Programs.
Each Subcategory has ONE Category
Each Subcategory has MANY Programs.
Then I believe that my answer is still valid. You see, my structure is the same as your description except Each Program has ONE Category (because rails has no belongs_to through). you has one is actually belongs_to (because it can belong to only one).
But as soon as Each Program has ONE Subcategory and Each Subcategory has ONE Category program's subcategory's category will be the ONLY program's category. You can have p.program_category by defining a method on a Program class:
def program_category
program_subcategory.program_category
end
Now for the part of
I should be able to retrieve and also EDIT these:
p.program_category
Imagine you have a Program in subcategory Comedy from category Movies.
You say you want to be able to EDIT programs category directly (if I understood correctly), like this:
p.program_category = ProgramCategory.find_by_name("Sports")
But what you expect to be program's subcategory then? As soon as Sports have many subcategories? Do you expect it to be blank?
So in this design the only way to change program's category is to change program's subcategory:
p.program_subcategory = ProgramSubcategory.find_by_name("Tennis")
And this will manke program's category == Sports, because Tennis belongs to Sports.
Note: If you really want sometimes to change program's category directly, leaving its subcategory blank it requires another design of course. I do not think it is very difficult but it requires more work with less help from Rails AR Associations magic.
EDIT3:
To wit, DO NOT put migration code in your model.rb files!!!
EDIT2: THE QUESTION (?) :
does ANY migration code belong in a model.rb file?
EDIT: Just mentioning extra (system/config/etc) information that I need to share in order to get a good answer to this question from someone (even if it's not you) would be greatly appreciated. (1-ups for good tips on stack overflow optimization strategies)
First of all, here is the command prompt activity:
C:\Users\davo\Desktop\RailsProjects\simple_cms>rails c
Loading development environment (Rails 3.2.3)
irb(main):001:0> subject = Subject.find(1)
←[1m←[36mSubject Load (1.0ms)←[0m ←[1mSELECT `subjects`.* FROM `subjects` WHERE `subjects`.`id` = 1
LIMIT 1←[0m
=> #<Subject id: 1, name: "Initial Subject", position: 1, visible: true, created_at:"2012-05-18 01:00:26", updated_at: "2012-05-18 01:11:21">
irb(main):002:0> subject.pages
(Object doesn't support #inspect)
The basic schema is that we have two models here, page.rb and subject.rb. Subject is the parent of Page, as you will see. Here are the two models.
Guide to viewing this code: I think all that is relevant to this problem in these two models are the has_many and belongs_to tags. And I admit, I feel like there should be some foreign keys here. Should there be foreign keys here? Or is that wrong too?
subject.rb
class Subject < ActiveRecord::Base
# attr_accessible :title, :body
has_many :pages
scope :visible, where(:visible => true)
scope :invisible, where(:visible => false)
scope :search, lambda {|query| where(["name LIKE ?", "%#{query}%"])}
end
page.rb
class Page < ActiveRecord::Base
has_many :sections
belongs_to :subject
# attr_accessible :title, :body
create_table "Pages" do |t|
t.string "name"
t.string "permalink"
t.integer "position"
t.boolean "visible?"
end
end
I'm really new at this, so please forgive me if I didn't give you some piece of information that you need. Please let let know what extra information you need, I'm not sure where the error is coming from but I know this is a model (M....VC) issue. 95% on that one.
You have a migration in your model.
create_table "Pages" do |t|
t.string "name"
t.string "permalink"
t.integer "position"
t.boolean "visible?"
end
Should be in ./db/migrate/{timestamp}_create_pages.rb. This file was generated for you if you did rails g model page
You also need a subject_id column to store the relation to subject
class CreatePages < ActiveRecord::Migration
def change
create_table :pages do |t|
t.integer :subject_id
t.string :name
t.string :permalink
t.integer :position
t.boolean :visible?
t.timestamps
end
end
end