how to save a belongs_to relationship? - ruby-on-rails

I have two models
class Course < AR::B
belongs_to :teacher
end
class Teacher < AR::B
has_one :course
end
So my table courses has one field teacher_id. I've a dropdown on courses to choose the teacher that works like a charm.
But I want to add a dropdown on the EDIT TEACHER screen also to change the course. I've tried with f.collection_select :course, Courses.all, :id, :name. This displays the dropdown, and on the controller:
teacher_params[:course] = Course.find(teacher_params[:course])
Beacause I was receiving an error Expecting Course got String. If i just try with #teacher.save. But this don't works neither
What is the right way to accomplish this?

In your form, be sure you are setting the database column (not the association)
= f.collection_select :course_id, Courses.all, :id, :name
^^^^^

on the edit page you should find the course by id and either assign the teacher_id directly, or find the teacher model as well and set it to Course#teacher.
assuming your params come back with something like
{ course: { id: 1, teacher_id: 5 } }
for option 1, your controller might look like
#course = Course.find(teacher_params[:id])
#course.teacher_id = teacher_params[:teacher_id]
or for option 2
#course = Course.find(teacher_params[:id])
#teacher = teacher_params[:teacher_id]
#course.teacher = #teacher
now saving the course should be fine

use:
class Teacher < AR::B
has_one :courses
end
you are using :course, it must be plural
and second thing f.collection_select :course, Courses.all, :id, :name
this is wrong here is correct way
f.collection_select :course, Course.all, :id, :name

Related

Rails - Can't create a record that has an attribute with the same name of the class

I'm having troubles trying to create (or even update) a database record, because both the parent class name and the name of an attribute are equal. I'm using a consolidated database, so I can't alter the tables.
I have a class Period with an attribute 'period'. One period has many tax scales.
#period model
has_many :tax_scales,
foreign_key: 'period',
primary_key: 'period'
#tax_scale model
belongs_to :period,
foreign_key: :period,
primary_key: :period
So, when I use this in my tax_scale view:
#new.html.haml
= f.label :period
= f.number_field :period
I get this error:
Period(#97477176) expected, got String(#8598408)
My controller params are:
params.require(:tax_scale).permit(:minimum, :maximum, ..., :period)
How can I edit (or create) a tax_scale record succesfully?
I found the solution: use methods using self[:attribute], to be sure the attribute is accessed
#tax_scale model
def current_period
self[:period]
end
def current_period=(p)
self[:period] = p
end
#new.html.haml
= f.label :current_period
= f.number_field :current_period
Notice I have to use self[:period] and not self.period, because the second one is still accessing the parent record, not the attribute.

Creating a form with nested attributes and prompt (has_many association)

So the issue is i have these classes.
class Post < ActiveRecord::Base
belongs_to :category
has_many :text_fields
has_many :integer_fields
accepts_nested_attributes_for :text_fields
accepts_nested_attributes_for :integer_fields
end
class Category < ActiveRecord::Base
has_many :fields
end
class TextField < ActiveRecord::Base
belongs_to :post
end
class IntegerField < ActiveRecord::Base
belongs_to :post
end
Category has many Fields, every field (not to confuse with TextField or IntegerField) has a column "type" (to specify if it is Text or Integer field) and description (eg. "how many pets do you have" for integerField). When User want to create a new post, first he chooses category. then, based on what Fields each category has, proper TextFields and IntegerFields should be build and rendered.
I hope my point is clear, i want to have Post generator which generate different fields based on category, simple as that.
Post form (without steps for now)
= simple_form_for #poster do |f|
= f.input :category_id, collection: Category.all, prompt: "Choose category"
= f.input :title
= f.simple_fields_for :text_fields do |ftf|
= ftf.input :description
= f.simple_fields_for :integer_fields do |fif|
= fif.input :integer_number
= f.submit
And heres whats wrong. i dont know how to give each field a proper prompt. each TextField or IntegerField is there just because Category requires it (based on fields). But can i make it has a proper prompt, not just 'integer number' every time?
Here's how i build those fields, its open for changes:
def build_fields_based_on_category
category.fields.each do |field|
self.send("#{field.kind}_fields").build
##### 'kind' can be integer or 'text'
end
end

Problems Using collection_select to store value in the database

I have two models:
Project.rb
class Project < ActiveRecord::Base
belongs_to :customer
end
and Customer.rb
class Customer < ActiveRecord::Base
has_many :projects
end
Inside the _form.html.erb I have:
<p>
<label>Select Customer</label>
<%= f.collection_select :customer_id, Customer.all, :id, :name, :include_blank => true %>
</p>
Which should Collect the Customers from the Customer model and display all the customers, finally it should assign the value to the customer_id which is in projects table.
Rite now the everything is passing when i check the log. When I select the first customer with value=1, it passes customer_id = "1" in my log but it doesn't get stored in the table. It shows customer_id = nil in the projects table.
Can someone help. Thanks :)
Do check that you added customer_id in attr_accessible method like,
class Project
attr_accessible :your_other_attributes, :customer_id
end

How to override enumeration data in rail_admin gem

In my models, BookHeader has many Category
So, when edit or create new BookHeader, the form show like this
Enum fix?
I wanna change the "category #{id}" to category name by define a category_enum method but it still don't work. Please help!
Code for BookHeader model
class BookHeader < ActiveRecord::Base
attr_accessible :autho, :category_id, :description, :title, :book_type, :year,:publisher_id,:detail
has_many :books
belongs_to :category
belongs_to :publisher
TYPE = {:ebook=>"Ebook",:paper_book=> "PaperBook",:magazine=> "Magazine",:media=> "Media"}
DEFAULT_TAB = :paper_book
BOOKS_PER_PAGE = 1 # books to show in a pages (pagination)
extend FriendlyId
def book_type_enum #it worked here
TYPE.map{|key, val| [val]}
end
def category_enum #but dont' work here
["a","b"]
end
Code for edit form
edit do
field :title
field :description, :text do
ckeditor do true end
end
field :autho
field :book_type
field :category
end
See the Division attribute in this link
alias_attribute :name, :you_field_you_want_to_display
I think it's more flexible way, there is no need to rename something and everything will work properly
Yeah, I just found the answer, rename a column in your model to "name", it seem to be very magical, but it worked!

Ruby on Rails collection_select complexity

i have the following Problem, i Have the following in my customer bill view
<%= f.collection_select :product_id,Product.all,:id,:name %>
This is getting list of all the products from "Product" model and giving option to select from it. But i want to select the list of products from the "StoreOpeningStock" model.
I have these in my model
class Product< ActiveRecord::Base
has_many :store_opening_stocks
has_many :customer_bills
attr_accessible :name
end
class StoreOpeningStock < ActiveRecord::Base
attr_accessible :product_id
belongs_to :product
end
class CustomerBill < ActiveRecord::Base
attr_accessible :product_id
belongs_to :product
accepts_nested_attributes_for :store_opening_stock
end
Can anyone guide me how i can get product name and id from store_opening_stock??? Should i use Helpers??? or is there any other way?? Thanks in advance
I tried using helpers
def getting_prod_names
#sto = StoreOpeningStock.all
for x in #sto
[
['{x.product.title}', '{x.product_id}']
]
end
end
getting following output
<%= f.select :product_id, options_for_select(getting_prod_names) %>
ANy Help?? :)
When you create a form the data used to ccreate a collection_select isnt limited to the Class your going to create an object for. You could simply do the following:
<%= f.collection_select :product_id,StoreOpeningStock.all,:product_id ,:name %>
This should to it for you,...
add this to your StoreOpeningStock class:
def name
return self.product.name unless self.product.nil?
""
end
You need to clarify the relationship between your models...
But just to give you an idea. You can define the collection of products you want to display in your controller, inside the action related to the view (where you are displaying the collection).
Controller:
#products= #here you should call all products you want
Then, your collection of products can be displayed like:
<%= f.collection_select :product_id, #products,:id,:name %>
EDIT
You need to revise the relationship between your models. A product has many customer_bills, but are you sure that each customer_bill belongs to a single product?
I think you have a many-to-many relationship, as a customer_bill can also have many products.
If I understand it right, the solution is to create a ProductLine model between this many-to-many relationship.
Also, what is the difference between Product and StoreOpeningStock? What attributes have you included in the StoreOpeningStock?
If you have created this model only to show the availability of products, why don't you add an attribute in the Product model, for example a boolean column called availability.
So you want to find all products that have a StoreOpeningStock.
This is solely a model concern and have nothing to do with helpers.
class Product
# Find all products that have a StoreOpeningStock
def self.in_stock
find(StoreOpeningStock.product_ids)
end
end
class StoreOpeningStock
# Collect all product ids from stocks
def self.product_ids
uniq.pluck(:product_id)
end
end
Now you can use Product.in_stock instead of Product.all to have the only ones in stock.
I'd add a scope to your products model:
class Product< ActiveRecord::Base
has_many :store_opening_stocks
has_many :customer_bills
attr_accessible :name
scope :having_store_opening_stocks, :joins => : store_opening_stocks, :select => 'distinct product.*', :conditions => 'store_opening_stocks.product > 0'
end
Then you can use Product.all.having_store_opening_stocks to select only products with such stocks, for example:
<%= f.select :product_id, Product.having_store_opening_stocks.map { |product| [product.name, product.id] } %>

Resources