I have three models: user, firm and revenue. I'd like to join the firm and revenue models, in order to publish the joined model results. Could someone please point me in the right direction on how to go about joining these tables and publish the results? Note, firm and revenue model can be joined through a unique_id number. Here is some of my code:
Revenue Model
class Revenue < ActiveRecord::Base
belongs_to :user
def self.import(file)
CSV.foreach(file.path, headers: true) do |row|
Revenue.create! row.to_hash
end
end
end
Firm Model
class Firm < ActiveRecord::Base
belongs_to :user
def self.import(file)
CSV.foreach(file.path, headers: true) do |row|
Firm.create! row.to_hash
end
end
end
User Model
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
before_save { self.email = email.downcase }
has_many :revenues
has_many :firms
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable,
:session_limitable, :confirmable
validates :name, :lastname, :industry, :company, :title, :address, :state, :city, :zip, presence: true
validates :phone, presence: true, length: { maximum: 11 }
end
Revenue DB
class CreateRevenues < ActiveRecord::Migration
def change
create_table :revenues do |t|
t.integer :unique_id
t.integer :revenue
t.integer :profit
t.references :user, index: true, foreign_key: true
t.timestamps null: false
end
end
end
Firm DB
class CreateFirms < ActiveRecord::Migration
def change
create_table :firms do |t|
t.integer :unique_id
t.string :name
t.string :state
t.string :city
t.references :user, index: true, foreign_key: true
t.timestamps null: false
end
end
end
View
<h2>Firm Data</h2>
<body>
<table>
<tr>
<th>unique_id</th>
<th>name</th>
<th>state</th>
<th>city</th>
</tr>
<body>
<% #firms.each do |firm| %>
<tr>
<td><%= firm.unique_id %> </td>
<td><%= firm.name %> </td>
<td><%= firm.state %> </td>
<td><%= firm.city %> </td>
<tr>
<% end %>
</table>
</body>
<h2>Revenue Data</h2>
<body>
<table>
<tr>
<th>unique_id</th>
<th>revenue</th>
<th>profit</th>
</tr>
<body>
<% #revenues.each do |rev| %>
<tr>
<td><%= rev.unique_id %> </td>
<td><%= rev.revenue %> </td>
<td><%= rev.profit %> </td>
<tr>
<% end %>
</table>
</body>
As per your question and comments it looks right to me to set up relationships as follow:
A user has_many firms (companies). A firm has_one revenue. A user has_many revenues through firms.
# app/models/user.rb
class User < ActiveRecord::Base
has_many :firms
has_many :revenues, through :firms
end
# app/models/firm.rb
class Firm < ActiveRecord::Base
has_one :revenue
end
# app/models/revenue.rb
class Revenue < ActiveRecord::Base
belongs_to :firm
end
Instead of storing a unique_id in both firms and revenues tables, it would be better to use a foreign_key in revenues, like firm_id.
The corresponding migrations are:
class CreateFirm < ActiveRecord::Migration
def change
create_table :firm do |t|
t.string :name
t.string :state
t.string :city
t.timestamps null: false
end
end
end
class CreateRevenue < ActiveRecord::Migration
def change
create_table :firm do |t|
t.belongs_to :firm, index: true
t.integer :revenue
t.integer :profit
t.timestamps null: false
end
end
end
This will enable you to use, for example, firm.revenue.profit to display the value of profit in the app/views/firms/show.html.erb view.
Looking at your models and migrations syntax it seems you are not using Rails 5. You can find Rails 4.2 docs about the has_one relationship here.
Related
Recently I installed devise_invitable to my application, I'm currently trying to figure out how to display the of the inviter.
In my view I'm trying to get the fullname of the user who sent an invite.
I tried the following:
Example.html.erb
<% #users.each do |user| %>
<%= user.fullname %> # Gives me the name of the user
<%= user.invited_by %> # Gives me ActiveRecord Association
<%= user.invited_by.fullname %> # Gives me an undefined method error
<% end %>
I would like to achieve this <%= user.invited_by.fullname %> is this possible?
Migration for devise_invitable
class DeviseInvitableAddToUsers < ActiveRecord::Migration[5.2]
def up
change_table :users do |t|
t.string :invitation_token
t.datetime :invitation_created_at
t.datetime :invitation_sent_at
t.datetime :invitation_accepted_at
t.integer :invitation_limit
t.references :invited_by, polymorphic: true
t.integer :invitations_count, default: 0
t.index :invitations_count
t.index :invitation_token, unique: true # for invitable
t.index :invited_by_id
end
end
def down
change_table :users do |t|
t.remove_references :invited_by, polymorphic: true
t.remove :invitations_count, :invitation_limit, :invitation_sent_at, :invitation_accepted_at, :invitation_token, :invitation_created_at
end
end
end
User Model
class User < ApplicationRecord
devise :invitable, :database_authenticatable, :registerable,
:recoverable, :rememberable, :validatable,
:confirmable, :omniauthable
validates :fullname, presence: true, length: { minimum: 4 }
validates_acceptance_of :terms_of_service
has_many :services
has_many :reservations
has_many :articles
has_many :lists
end
My guess is that not all of your users are invited by someone, so you need to check if invited_by is present first:
<% #users.each do |user| %>
<%= user.fullname %>
<% if user.invited_by.present? %>
<%= user.invited_by %>
<%= user.invited_by.fullname %>
<% end %>
<% end %>
Also when you send the invitation be sure that you are passing which user is sending the invite, since this parameter is optional:
User.invite!({:email => "new_user#example.com"}, current_user) # current_user will be set as invited_by
I have many images(add_images_to_steps) belonging to steps which belongs to diys. All information saves correctly as DB browser shows, but i have problem viewing images.
with
views/diys/show.html.erb
<p id="notice"><%= notice %></p>
<h2><%= #diy.summary %></h2>
<% #steps.each do |step| %>
<p><%= step.step_content %></p>
<% step.add_images_to_steps.each do |i| %>
<%= image_tag i.image_url.to_s %>
<% end %>
<% end %>
I get NoMethodError in Diys#Show
undefined method `image_url' for #
and if I change
to
I get this
-----------------------------------------------------------------------
Heres My migrations, models and controllers.
-----------------------------------------------------------------------
diys_controller.rb
class DiysController < ApplicationController
before_action :set_diy, only: [:show, :edit, :update, :destroy]
def show
#diy = Diy.find(params[:id])
#steps = #diy.steps.all
#diy.add_images_to_steps.all
end
def new
#diy = Diy.new
#step = #diy.steps.new
#step.add_images_to_steps.new
end
...
def diy_params
params.require(:diy).permit(:title, :summary, :tip, :warning, steps_attributes: [:step_content, add_images_to_steps_attributes: [:image]])
end
models/diy.rb
class Diy < ActiveRecord::Base
has_many :steps, dependent: :destroy
accepts_nested_attributes_for :steps, reject_if: :all_blank
has_many :add_images_to_steps, :through => :steps, dependent: :destroy
accepts_nested_attributes_for :add_images_to_steps
end
models/step.rb
class Step < ActiveRecord::Base
belongs_to :diy
has_many :add_images_to_steps, dependent: :destroy
accepts_nested_attributes_for :add_images_to_steps
mount_uploader :image, ImageUploader
end
models/add_images_to_step.rb
class AddImagesToStep < ActiveRecord::Base
belongs_to :step
end
Diy migration
class CreateDiys < ActiveRecord::Migration
def change
create_table :diys do |t|
t.string :title
t.text :summary
t.text :tip
t.text :warning
t.timestamps null: false
end
end
end
Steps migration
class CreateSteps < ActiveRecord::Migration
def change
create_table :steps do |t|
t.belongs_to :diy
t.text :step_content
t.timestamps null: false
end
end
end
add_images_to_step migration
class CreateAddImagesToSteps < ActiveRecord::Migration
def change
create_table :add_images_to_steps do |t|
t.belongs_to :step
t.string :image
t.timestamps null: false
end
end
end
I figured it out!!
Had to add
mount_uploader :image, ImageUploader
to ../models/add_images_to_step.rb
change def store_dir to
"#{Rails.root}/public/uploads/"
in ../app/uploaders/image_uploader.rb
and
"<%= image_tag i.image_url.to_s %>"
was right for show view.
I have successfully implemented the dynamic select menus for city and area models in my app.
now I have the following models:
class Pet < ActiveRecord::Base
belongs_to :pet_type
belongs_to :pet_category
belongs_to :pet_breed
end
class PetType < ActiveRecord::Base
has_many :pet_categories, through: :pet_type_categories
has_many :pet_type_categories
end
class PetCategory < ActiveRecord::Base
has_many :pet_types, through: :pet_type_categories
has_one :pet_type_category
end
class PetTypeCategory < ActiveRecord::Base
belongs_to :pet_type
belongs_to :pet_category
has_many :pet_breeds
end
class PetBreed < ActiveRecord::Base
belongs_to :pet_type_category
belongs_to :pet_Type
belongs_to :pet_category
end
migrations:
class CreatePetTypes < ActiveRecord::Migration
def change
create_table :pet_types do |t|
t.string :name
t.timestamps
end
end
end
class CreatePetCategories < ActiveRecord::Migration
def change
create_table :pet_categories do |t|
t.string :name
t.timestamps
end
end
end
class CreatePetTypeCategories < ActiveRecord::Migration
def change
create_table :pet_type_categories do |t|
t.references :pet_type, index: true
t.references :pet_category, index: true
t.timestamps
end
end
end
class CreatePetBreeds < ActiveRecord::Migration
def change
create_table :pet_breeds do |t|
t.string :name
t.references :pet_type_category, index: true
t.timestamps
end
end
end
The pet_type_category table is a join table for pet_types that share the same pet_categories.
So my question is how do I create 3 dynamic select menus of pet_type, pet_category and pet_breed in the create form?
Thanks
Edit: I managed to get the pet type collection_select and pet category grouped_collection_select done once I updated the relationships, now the 3rd one (pet breed) is what I'm stuck at..
I understand now after a bit of a research that it is not possible to have nested groups though surely It should be possible using some kind of helper, however for a lack of a better solution, I added to the PetTypeCategory model:
def pet_type_category_names
"#{self.pet_type.name} #{self.pet_category.name}"
end
and in my view now I have:
<div class="field">
<%= f.collection_select :pet_type_id, PetType.all, :id, :name, {prompt: "Choose your pet's type"} %>
</div>
<div class="field">
<%= f.grouped_collection_select :pet_category_id, PetType.all, :pet_categories, :name, :id, :name, {prompt: "Choose your pet's category"} %>
</div>
<div class="field">
<%= f.grouped_collection_select :pet_breed_id, PetTypeCategory.all, :pet_breeds, :pet_type_category_names, :id, :name, {prompt: "Choose your pet's breed"} %>
</div>
so for the 3rd select instead of having:
Dog
Small
Breed
I have:
Dog Small
Breed
Not sure how to delete the associate between 'fly' and 'invoice'. What I've tried so far deletes the fly from the database
<table class="table table-condensed">
<thead>
<tr>
<th>Invoice Flies</th>
</thead>
<tbody>
<% #invoice.flies.each do |fly| %>
<tr>
<td><%= fly.name %></td>
<td><%= link_to "delete", ??????, method: :delete,
data: { confirm: "You sure?" } %></td>
</tr>
<% end %>
</tbody>
</table>
Invoice Model:
class Invoice < ActiveRecord::Base
attr_accessible :active
validates :user_id, presence: true
belongs_to :user
has_many :categorizations
has_many :flies, through: :categorizations
end
Invoice migration:
class CreateInvoices < ActiveRecord::Migration
def change
create_table :invoices do |t|
t.boolean :active
t.integer :user_id
t.timestamps
end
add_index :invoices, :user_id
end
end
Categorization Model:
class Categorization < ActiveRecord::Base
attr_accessible :fly_id, :user_id
belongs_to :invoice
belongs_to :fly
end
Categorization migration:
class CreateCategorizations < ActiveRecord::Migration
def change
create_table :categorizations do |t|
t.integer :user_id
t.integer :fly_id
t.timestamps
add_index :categorizations, :user_id
add_index :categorizations, :fly_id
end
end
end
Fly Model:
class Fly < ActiveRecord::Base
attr_accessible :description, :name
validates :description, :name, presence: true
has_many :categorizations
has_many :invoices, through: :categorizations
end
Fly migration:
class CreateFlies < ActiveRecord::Migration
def change
create_table :flies do |t|
t.string :name
t.string :description
t.timestamps
end
end
end
You can use dependent: :destroy like this:
class Fly
has_many :categorizations, dependent: :destroy
...
end
This will destroy the categorizations related to that Fly.
Also, remember to use Fly.destroy(:id) (DO NOT USE Fly.delete(:id), or it won't remove the categorizations dependent on that Fly)
So I'm relatively new to Rails, but have been trying to build a little store to sell some things for bitcoin. When I run my storefront on my local environment my pricing looks great (i.e. a book for .001 BTC), yet when I push it live to Heroku, my price rounds itself to the nearest 100th.(i.e. .016 becomes .02 or .001 becomes .00). Any ideas? Here is my product.rb file that validates my ":price".
class Product < ActiveRecord::Base
attr_accessible :price, :title, :image_url, :description, :orders
has_many :line_items
has_many :orders, through: :line_items
before_destroy :ensure_not_referenced_by_any_line_item
validates :title, :description, :image_url, presence: true
validates :price, numericality: {greater_than_or_equal_to: 0.00000001}
validates :title, uniqueness: true
validates :image_url, allow_blank: true, format: {
with: %r{\.(gif|jpg|png)$}i,
message: 'must be a URL for GIF, JPG, or PNG image.'
}
Here is my _line_item.html.erb file:
<% if line_item == #current_item %>
<tr id="current_item">
<% else %>
<tr>
<% end %>
<td><%= line_item.quantity %>×</td>
<td><%= line_item.product.title %></td>
<td class="item_price"><%= line_item.total_price %> BTC</td>
</tr>
My code is based on the Agile Web Development with Rails book's Depot app... Thanks for any help!
After further inspection of my DB migration (depot/db/timestamp_create_products.rb), I realize that I had set the precision to 8 and the scale to 2:
class CreateProducts < ActiveRecord::Migration
def change
create_table :products do |t|
t.string :title
t.text :description
t.string :image_url
t.decimal :price, precision: 8, scale: 2
t.timestamps
end
end
end
So I just had to change that to this:
class CreateProducts < ActiveRecord::Migration
def change
create_table :products do |t|
t.string :title
t.text :description
t.string :image_url
t.decimal :price, precision: 9, scale: 8
t.timestamps
end
end
end
Thanks for telling me where I needed to look Rich and Mike!