I'm new to Rails and trying to create an C2C marketplace App just to understand how rails works and start some real project later on.
The idea is that User can place Order to other User. Orders is related with user's Printer (you choice user where you want to print on /order page). Printer in its turn have many colors to print
For now, Im stack with very basic things.
I want to display list of all printers with owner's name and colors available on /order page in Orders controller. Thank you in advance for any ideas how I can do this
class User < ActiveRecord::Base
has_many :printers, dependent: :destroy
has_many :orders, dependent: :destroy
end
class Order < ActiveRecord::Base
belongs_to :user
validates :user_id, presence: true
end
class Printer < ActiveRecord::Base
belongs_to :user
validates :user_id, presence: true
validates :model, presence: true, allow_nil: true
has_many :materials, dependent: :destroy
end
Orders controller with index action (/orders)
class OrdersController < ApplicationController
def index
#printers = Printer.all
end
end
And index.html.erb
<% #printers.each do |p| %>
<div class="col-xs-9">
<div><%= "USERNAME HERE" %></div> <!--Do not know how to display parent's model here? -->
<div><%= p.model %></div> <!--Works fine-->
<div><%= p.colors.each do |c| c.color end %></div> <!--Display array instead of strings-->
</div>
<div class="col-xs-3">
<button>Order</button>
</div>
<% end %>
Simplified schema.db
ActiveRecord::Schema.define(version: 20160627132435) do
create_table "colors", force: :cascade do |t|
t.string "color"
t.integer "printer_id"
end
create_table "orders", force: :cascade do |t|
t.string "price"
t.string "status"
t.integer "user_id"
end
create_table "printers", force: :cascade do |t|
t.string "model"
t.integer "user_id"
end
add_index "printers", ["user_id"], name: "index_printers_on_user_id", using: :btree
create_table "users", force: :cascade do |t|
t.string "first_name"
t.string "last_name"
end
add_foreign_key "orders", "users"
add_foreign_key "printers", "users"
end
I think you should be able to do:
<% #printers.each do |p| %>
<div class="col-xs-9">
<div><%= p.user.first_name %></div> <!--Do not know how to display parent's model here? -->
<div><%= p.model %></div> <!--Works fine-->
<div><% p.colors.each do |c|
<%= c.color %>
<% end %></div> <!--Display array instead of strings-->
</div>
<div class="col-xs-3">
<button>Order</button>
</div>
<% end %>
Related
I am creating a self referential relationship for services. The idea is to allow you to add a potentially infinite level of sub services to a service, so services can have children, and those children can have children, etc.
To do this I have crated two classes, Services, and SubServices. SubServices is a simple join table with a parent_service_id and a child_service_id. I am able to create everything in the rails console and it works just fine. Both the child and parent associations work. It's just in the controller that it's breaking down
schema:
create_table "services", force: :cascade do |t|
t.string "name"
t.integer "business_category_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["business_category_id"], name: "index_services_on_business_category_id", using: :btree
end
create_table "sub_services", force: :cascade do |t|
t.integer "child_service_id"
t.integer "parent_service_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["child_service_id"], name: "index_sub_services_on_child_service_id", using: :btree
t.index ["parent_service_id"], name: "index_sub_services_on_parent_service_id", using: :btree
end
models:
class SubService < ApplicationRecord
belongs_to :parent_service, class_name: 'Service'
belongs_to :child_service, class_name: 'Service'
end
class Service < ApplicationRecord
belongs_to :business_category
has_many :client_services # TODO REMOVE
has_many :clients, :through => :client_services # TODO REMOVE
has_many :business_services
has_many :businesses, :through => :business_services
has_many :parental_services, foreign_key: :parent_service_id, class_name: "SubService"
has_many :child_services, through: :parental_services
has_many :children_services, foreign_key: :child_service_id, class_name: "SubService"
has_many :parent_services, through: :children_services
validates :name, presence: true
validates :name, uniqueness: { scope: :business_category, message: "service already added" }
end
SubService new action:
def new
#sub_service = #service.child_services.new
respond_to do |format|
format.html
format.js { render :new }
end
end
SubService create action:
def create
#sub_service = #service.child_services.new(service_params);
# binding.pry
if #sub_service.save
redirect_to(admin_business_categories_path)
end
end
service_params:
def service_params
params.require(:sub_service).permit(:name)
end
Sub Service new view:
<%= render 'form', f: f %>
<% end %>
_form:
<div class="col-12 col-md-10">
<div class="col-12 col-md-12">
<%= f.input :name, label: 'Service Name' %>
</div>
</div>
<div class="col-12 col-md-2">
<div class="btn-group-vertical" role="group" aria-label="...">
<button id="serviceFormCancelButton" class="btn btn-danger">CANCEL</button>
<%= f.submit 'SAVE', class: 'btn btn-success' %>
<br>
</div>
</div>
This is the error my console is returning
ActiveModel::UnknownAttributeError (unknown attribute 'parent_service_id' for Service.):
app/controllers/admin/sub_services_controller.rb:14:in `create'
Rendering C:/Ruby24-x64/lib/ruby/gems/2.4.0/gems/actionpack-5.0.7/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb within rescues/layout
Rendering C:/Ruby24-x64/lib/ruby/gems/2.4.0/gems/actionpack-5.0.7/lib/action_dispatch/middleware/templates/rescues/_source.html.erb
Rendered C:/Ruby24-x64/lib/ruby/gems/2.4.0/gems/actionpack-5.0.7/lib/action_dispatch/middleware/templates/rescues/_source.html.erb (3.0ms)
Rendering C:/Ruby24-x64/lib/ruby/gems/2.4.0/gems/actionpack-5.0.7/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb
Rendered C:/Ruby24-x64/lib/ruby/gems/2.4.0/gems/actionpack-5.0.7/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb (2.0ms)
Rendering C:/Ruby24-x64/lib/ruby/gems/2.4.0/gems/actionpack-5.0.7/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb
Rendered C:/Ruby24-x64/lib/ruby/gems/2.4.0/gems/actionpack-5.0.7/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb (1.0ms)
Rendered C:/Ruby24-x64/lib/ruby/gems/2.4.0/gems/actionpack-5.0.7/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb within rescues/layout (846.1ms)
You want a Service > SubService and then potentially Service > SubService > SubService > SubService.... right? You're getting the unkown attribute error because parent_id is on SubService. You can do what you want with just the Service model. Just put the parent_id on that.
You could then get rid of the SubService model.
class Service
belongs_to :parent_service, foreign_key: :parent_id, class_name: 'Service'
has_many :child_services, class_name: 'Service'
end
I currently have 3 models (user, pairing, meetings), and the join table meetings_pairings.
User.rb
class User < ActiveRecord::Base
enum role: [:student, :supervisor, :admin]
has_many :students, class_name: "User",
foreign_key: "supervisor_id"
belongs_to :supervisor, class_name: "User"
has_and_belongs_to_many :pairings
end
Pairings.rb
class Pairing < ActiveRecord::Base
has_and_belongs_to_many :supervisor, class_name: 'User'
belongs_to :student, class_name: 'User'
has_and_belongs_to_many :meetings, join_table: :meetings_pairings
end
Meetings.rb
class Meeting < ActiveRecord::Base
enum status: [:available, :unavailable]
has_and_belongs_to_many :pairings, join_table: :meetings_pairings
end
Schema.rb (relevant bits)
create_table "meetings", force: :cascade do |t|
t.date "meeting_date"
t.datetime "meeting_time"
t.integer "status", default: 0, null: false
t.boolean "accepted"
end
create_table "meetings_pairings", id: false, force: :cascade do |t|
t.integer "pairing_id"
t.integer "meeting_id"
end
add_index "meetings_pairings", ["meeting_id"], name: "index_meetings_pairings_on_meeting_id"
add_index "meetings_pairings", ["pairing_id"], name: "index_meetings_pairings_on_pairing_id"
create_table "pairings", force: :cascade do |t|
t.integer "supervisor_id"
t.integer "student_id"
t.string "project_title"
end
add_index "pairings", ["student_id"], name: "index_pairings_on_student_id", unique: true
add_index "pairings", ["supervisor_id"], name: "index_pairings_on_supervisor_id"
I created the view and controller to enable a user (supervisor, which is in a pairing) to create a meeting. However I don't know how to add this association to the join table.
meetings_controller.rb
class MeetingsController < ApplicationController
def index
#meetings = Meeting.all
end
def new
#meeting = Meeting.new
end
def create
#meeting = Meeting.new(meeting_params)
if #meeting.save
redirect_to meetings_path, :notice => "Meeting Created!"
else
redirect_to meetings_path, :notice => "Meeting Failed!"
end
end
def show
#meeting = Meeting.find(params[:id])
end
private
def meeting_params
params.require(:meeting).permit(:meeting_date, :meeting_time)
end
end
Form from the view
<%= form_for #meeting do |f| %>
<div class="field">
<%= f.label :meeting_date %><br />
<%= f.text_field :meeting_date %>
</div>
<div class="field">
<%= f.label :meeting_time %><br />
<%= f.time_select :meeting_time, :ampm => true, :minute_step => 30, :default => {:hour => '9', :minute => '0'} %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
This creates an entry in the meetings table, so my question is how can I make it so that an entry is made into the join table with the pairing id of the current user who created the meeting ?
Decided to use a has_many :through (user-meeting-user) relationship instead. Question no longer relevant.
So, I have 3 models Quotes, Categories, and Subscribers.
Essentially, it's a newsletter application. Subscribers can select a category and then enter their email and they will receive quotes related to that category via email.
There's two issues here,
1. The category's are stored in a constant in the category model.
so how do I display the category type that the subscriber chose
in text format? I'd like to show in the email
something like "here's your email on <%= category.name %>" which would translate to
"here's your email on Food."
2. I'd like to ONLY send emails about the category that the subscriber subscribed to.
How might I accomplish this? Please provide examples.
This is what I have so far:
Category.rb
class Category < ActiveRecord::Base
belongs_to :quote
belongs_to :subscriber
CATEGORY_TYPE = {
1 => "Food",
2 => "Fitness",
3 => 'Cats',
}
end
Quote.rb
class Quote < ActiveRecord::Base
has_many :categories
belongs_to :category
validates :title, presence: true
end
Subscriber.rb
class Subscriber < ActiveRecord::Base
has_one :category
validates :email, presence: true
end
schema
create_table "categories", force: true do |t|
t.string "name"
t.integer "quote_id"
t.datetime "created_at"
t.datetime "updated_at"
t.integer "subscriber_id"
t.integer "category_type"
end
create_table "quotes", force: true do |t|
t.string "title"
t.text "body"
t.datetime "created_at"
t.datetime "updated_at"
end
create_table "subscribers", force: true do |t|
t.string "email"
t.datetime "created_at"
t.datetime "updated_at"
end
Update subscribers_mailer.rb
def SendMyEmail(email, category, quote, subscribers)
#category = category
#quote = quote
#subscribers = subscribers
#email = email
mail to: email, subject: 'New Quotes'
end
end
and then of course:
Category.all.each do |category|
SubscriptionMailer.SendMyEmail("email#test.com", category, category.quotes.first, category.subscribers).deliver
end
Update:
There's two remaining issues here,
1. Categories aren't syncing to subscribers. For example when I run category.subscribers.last
it's nil. and category.subscribers throws an empty array. How can I sync these? I think it has
to do with the fact that subscribers are selecting a category from the Category::CATEGORY_TYPES
constant as seen in the view code below.
2. I'd like to automate it so that these emails are sent to subscribers once a day.
How might I do this?
view code (subscribers/new.html.erb:
<div class="styled email-input2">
<%= form_for #subscriber do |f| %>
<% if #subscriber.errors.any? %>
<div class="errorExplanation" style="color: white;">
<h2><%= pluralize(#subscriber.errors.count, 'error') %> encountered:</h2>
<ul>
<% #subscriber.errors.full_messages.each do |m| %>
<li><%= m %></li>
<% end %>
</ul>
</div>
<% end %>
<%= f.fields_for :subscriber, #subscriber.build_category do |cat| %>
<%= cat.select(:category_type, Category::CATEGORY_TYPE.map{|p| [p[1], p[0]]}, {prompt: 'Please select'}, {class: 'styled email-input2'}) %>
<% end %>
</div>
Ok first lets modify the migrations:
create_table "categories", force: true do |t|
#DELETE QUOTE_ID AND SUBSCRIBER ID
t.string "name"
t.datetime "created_at"
t.datetime "updated_at"
t.integer "category_type"
end
create_table "quotes", force: true do |t|
t.string "title"
t.text "body"
t.datetime "created_at"
t.datetime "updated_at"
t.references :category #this will add integer category_id
end
create_table "subscribers", force: true do |t|
t.string "email"
t.datetime "created_at"
t.datetime "updated_at"
t.references :category #this will add integer category_id
end
Next we will modify the models to reflet the changes in the migration:
class Category < ActiveRecord::Base
has_many :quotes
has_many :subscribers
CATEGORY_TYPE = {
1 => "Food",
2 => "Fitness",
3 => 'Cats',
}
end
class Quote < ActiveRecord::Base
belongs_to :category
validates :title, presence: true
end
class Subscriber < ActiveRecord::Base
belongs_to :category
validates :email, presence: true
end
Now you can get the subscribers for a cateogyr using the following:
category = Category.find(1) #use whatever id you want
category.subscribers #list of all subscribers for a category
Getting the quotes for a category is similarly straight forward:
category = Category.find(1)
category.quotes
So assuming your mailer takes a category, quote and a list of subscribers for the email to send
Category.all.each do |category|
Mailer.SendMyEmail(category, category.quotes.first, category.subscribers).deliver
end
In the "SendMyEmail" function in your mailer you will have
def SendMyEmail(category, quote, subscribers)
#YOUR CODE FOR TYHE VIEW HERE
end
I am trying to figure out how to register certain values to their respective table using the form, check the order form to better understand which values need to be registering to which table.
I have also displayed the table entries, models and controller related to this question. If someone can guide me to where I can obtain further understanding on coding the associations in forms that would be great.
order form
<%= simple_form_for(#order) do |f| %>
<%= f.association :items, collection: Item.all, label_method: :name, value_method: :id %>
<%= [need to display the price of the item selected] %>
<%= f.input :quantity ???? [need to register in the order_items table] %>
<%= [register sub total to orders table] %>
<%= f.submit %>
<% end %>
tables
create_table "order_items", force: true do |t|
t.integer "item_id"
t.integer "order_id"
t.integer "quantity"
end
create_table "orders", force: true do |t|
t.integer "user_id"
t.integer "client_id"
t.boolean "status"
t.decimal "sub_total"
end
create_table "items", force: true do |t|
t.string "name"
t.decimal "price"
t.integer "stock"
end
models
class Order < ActiveRecord::Base
...
has_many :order_items
has_many :items, :through => :order_items
end
class Item < ActiveRecord::Base
...
has_many :order_items
has_many :orders, :through => :order_items
end
class OrderItem < ActiveRecord::Base
belongs_to :item
belongs_to :order
end
orders controller
def create
#order = Order.new(order_params)
#order.user_id = current_user.id
#order.status = TRUE
end
def order_params
params.require(:order).permit(:code, :client_id, :user_id, :memo, :status, item_ids: [])
end
I am now trying to show the images, which a user already registered, on his or her 'mypage'.
Then, I wrote some codes as below.But it doesn't work.Could you give me some advises?
☆members_controller
#member= Member.find(params[:id])
#member.groups.reverse.map do |group|
#join_groups_images = group.imageurl
☆(members)show.html.erb
<div class="join_groups_images">
<%= image_tag #join_groups_images, :width => '20px' ,:height => '25px' %>
</div>
☆(model)member.rb
class Member < ActiveRecord::Base
attr_accessible :admin, :mail, :memo, :name, :pass, :user, :pass_confirmation
has_many :group_in_members, :dependent => :destroy
has_many :groups, :through => :group_in_members
☆(model)group_in_member.rb
class GroupInMember < ActiveRecord::Base
attr_accessible :group_id, :member_id
belongs_to :group
belongs_to :member
end
☆schema.rb
create_table "groups", :force => true do |t|
t.string "name"
t.text "memo"
t.boolean "admin"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
t.string "imageurl"
end
You didn't provide whole code from action in members controller, but I assume, that you are using .map{|| } in wrong way. You need a variable with array or even method in Member model.
class Member < ActiveRecord::Base
...
def images
groups.reverse.map(&:imageurl)
end
...
end
and then, put this in your view
<ul class="join_groups_images">
<% #member.images.each do |image| >
<li><%= image_tag image %></li>
<% end>
</div>
that should do the trick.