I'm experiecing some problems with option_from_collection_for_select when the selected value is nil.
I have User model:
class User < ActiveRecord::Base
attr_accessible :email, :password, :password_confirmation, :remember_me, :username, :locale
end
and a Reservation one:
class Reservation < ActiveRecord::Base
belongs_to :user
end
In the reservation add/edit page there is a select with the user is goiing to be associated with the reservation:
<%= select_tag('user_id',
options_from_collection_for_select(#users, :id, :username, #reservation.user.id)) %>
This works in the edit page when #reservation.user.id is not nil but I get the nil error in the add page.
Just for now I check if #reservation.user.id is nil and I put the selected value depending if is nil or not; this works but I don't like this solution.
How can I solve this?
There are probably many ways around this:
At the very least, you'd have to put a conditional for the last argument for ofcfs.
options_from_collection_for_select(
#users, :id, :username,
#reservation.user.blank? ? 0 : #reservation.user.id)
Then, in your create action, you'd have to prepend an appropriate hash:
#users = User.all
#users.insert(0, {:id=>0,:username=>'PLEASE SELECT A USER'})
Then you'd have to validate that the value returned from the select isn't 0 before you save a reservation.
There are at least three or four other things I can think of that work around this
Related
I have an app that has 2 models that need a many to many relationship. I originally tried using has_and_belongs_to_many but it wasn't working. After scrummaging through the internet I was convinced that this was not what I needed anyhow. So, I switched to a has_many through method. However, this isn't working either. I am now at a major loss on what the issue is. I have ripped it out many times and tried tutorial after tutorial but to no avail.
The models I am trying to connect are Message and Author. In my most recent attempt, I created a joining model (with corresponding table) called Authoring. Here is my code:
message.rb
has_many :authorings
has_many :authors, through: :authorings
author.rb
has_many :authorings
has_many :messages, through: :authorings
authoring.rb
belongs_to :message
belongs_to :author
messages_controller.rb
def messages_params
params.require(:message).permit(:title, :summary, :date, :duration, :youversion, :hours, :minutes, :seconds, :authors)
end
My Messages form:
<%= f.label :speakers %><br />
<%= collection_select(:authors, :authors, Author.all, :id, :name, {}, {:multiple => true, :size => 10}) %>
When I created a new message, this showed in the log:
Parameters: {"utf8"=>"✓", "authenticity_token"=>"OcLeke/eRRzwApoMSgQF81kBCm7TaGxW1PoVAUgEcvo=", "message"=>{"title"=>"Test1", "summary"=>"This is my test summary.", "date(2i)"=>"8", "date(3i)"=>"25", "date(1i)"=>"2014", "date(4i)"=>"01", "date(5i)"=>"00", "hours"=>"0", "minutes"=>"58", "seconds"=>"52", "youversion"=>""}, "authors"=>{"authors"=>["", "1"]}, "commit"=>"I'm Finished", "id"=>"1"}
The form obviously recognizes the authors in the form but it doesn't save them in the database. What is my disconnect? Please help!!!
Thanks!
authors records are not getting created because the controller is expecting authors to be present within message key's value in params hash BUT if you notice the params hash in the log
Parameters: {"utf8"=>"✓",
"authenticity_token"=>"OcLeke/eRRzwApoMSgQF81kBCm7TaGxW1PoVAUgEcvo=",
"message"=>{...}, "authors"=>{...}, "commit"=>"I'm Finished",
"id"=>"1"}
you would see that authors is coming as an altogether separate key in params hash which is why it is being ignored.
What you need to do is associate the authors with the form object, instead of using collection_select you need to use f.collection_select as shown below. Specify the first argument as :author_ids in f.collection_select.
<%= f.collection_select(:author_ids, Author.all, :id, :name, {}, {:multiple => true, :size => 10}) %>
As you have :multiple => true option specified, you would receive authors as an Array in the params hash. You need to permit author_ids as an Array in message_params method
def messages_params
params.require(:message).permit(:title, :summary, :date, :duration, :youversion, :hours, :minutes, :seconds, :author_ids => [])
end
Models:
A User has_one Ucellar
A Ucellar belongs_to User
I have confirmed from multiple sources that these are set up correctly. For posterity, here is the top portion of those two models.
class User < ActiveRecord::Base
has_many :authorizations
has_one :ucellar
validates :name, :email, :presence => true
This is actually the entire Ucellar model.
class Ucellar < ActiveRecord::Base
belongs_to :user
end
Ucellar has a column called user_id, which I know is necessary. The part of my application that creates a user uses the method create_with_oath. Below is the entire User class. Note the second line of the create method.
class User < ActiveRecord::Base
has_many :authorizations
has_one :ucellar
validates :name, :email, :presence => true
def create
#user = User.new(user_params)
#ucellar = #user.create_ucellar
end
def add_provider(auth_hash)
# Check if the provider already exists, so we don't add it twice unless authorizations.find_by_provider_and_uid(auth_hash["provider"], auth_hash["uid"])
Authorization.create :user => self, :provider => auth_hash["provider"], :uid => auth_hash["uid"]
end
end
def self.create_with_omniauth(auth)
user = User.create({:name => auth["info"]["name"], :email => auth["info"]["email"]})
end
private
def user_params
params.require(:user).permit(:name, :email)
end
end
EDIT:
Forgot to summarize the symptoms. On create, the user is in the db, with no exceptions thrown, and nothing to signify that anything went wrong. However, the related ucellar is never created. Per the documentation Here, the create method should create AND save the related ucellar.
It should create ucellar too.
Try to get the error messages after the creation by calling:
raise #user.errors.full_messages.to_sentence.inspect
I'm not sure why this wasn't working, but I ended up just moving this code out of the create action of the user controller, and putting it directly after an action that was creating a user. It solved my issue though. Thanks everyone for your help!
I am working on a Sinatra image app. I have defined Datamapper models for my users, the uploaded images, and "Favs". Each user can give a maximum of one "Fav" to each image.
class User
include DataMapper::Resource
property :id, Serial
property :privilege_lvl, Integer, :default => 0
property :name, String, :unique => true
property :password_hash, BCryptHash
has n, :images
has n, :comments
has n, :favs
end
class Image
include DataMapper::Resource
property :id, Serial
mount_uploader :file, ImageUploader
belongs_to :user
property :posted_at, DateTime
has n, :comments
has n, :favs
end
class Fav
include DataMapper::Resource
property :id, Serial
belongs_to :image
belongs_to :user
end
Is there a way to count the total number of Favs a user has received without iterating over all the images of the user and summing up the Favs of each image?
Sounds like you need a counter cache:
This could be as simple as adding a :favs_cache to users and incrementing it whenever favs are added.
You might also want to check out this gem: dm-counter-cache
I don't get why I'm getting this error
undefined method `sector_id' for #<Portfolio:0x007fe17c2e3848>
I have a Portfolio Model and a Sector model, they look like so
class Portfolio < ActiveRecord::Base
belongs_to :sector
attr_accessible :overview, :title, :sector_id
end
class Sector < ActiveRecord::Base
has_many :portfolios
attr_accessible :name
end
My routes
resources :portfolios do
resources :sectors
end
So within my form to create a new portfolio I have this collection_select
<%= f.label :sector_id, "Choose Sector", :class => 'title_label' %><br>
<%= f.collection_select(:sector_id, Sector.all, :id, :name, :prompt => "Please Select a Sector") %>
This is something I've done many times before and it has worked, can anyone see why I would be getting this error?
The only thing I can think of is that I have called my controller for portfolio as Portfolios, I always get mixed up with plural and singular controller names, would this make a difference in my case?
Maybe you have not run the migration yet that adds the column "sector_id" in your table "portfolios". If you are using MySQL connect to your database and check the table (show create table portfolios;). Use appropriate method to get this info from your database server if you are using other rdbms. Alternatively, in your rails console (rails c) type in Portofolio and see what attributes it prints out. Does it include sector_id?
I have the following 4 models
Hotel (name)
has_one :address
has_one :contact
has_one :bank_account
validates_presence_of :name
def build_dependencies
build_contact
build_address
build_bank_account
end
Address (phone, street_address, hotel_id)
belongs_to :hotel
validates_presence_of :phone, :street_address
Contact (name, email, hotel_id)
belongs_to :hotel
validates_presence_of :name, :email
BankAccount (name, number, hotel_id)
belongs_to :hotel
validates_presence_of :name, :number
In a form used to create a Hotel, I take input for both name and email for the Contact model but only phone for the Address model.
HotelController#new
#hotel = Hotel.new
#hotel.build_dependencies #this creates empty Contact and Address to generate the form fields
#render the form to create the hotel
HotelController#create
#receive form data
#hotel = Hotel.new
#hotel.build_dependencies
#hotel.save :validate => false
#hotel.attributes = params[:hotel]
#hotel.save :validate => false
This is the only way I was able to create a Hotel with contact information, phone from address and empty bank account. I had to call
#hotel.save :validate => false
the first time to save the Hotel instance with blank instances of BankAccount, Address, Contact. Then I had to update_attributes on contact and address and then
#hotel.save :validate => false
to ensure that the original form data got saved completely as expected.
This, beyond doubt, is a very bad piece of code. Can anyone tell me how to clean this up?
You can use a filter, namely the after_create to call the associated model to create associated records after saving of the #hotel variable.
I happen to be facing the same problem and here's my solution. Sorry this probably is not helpful after such a long while but it'll be good for future users.
class User < ActiveRecord::Base
has_one :bank_account
# Filter -- After Creation
after_create :create_default_bank_account
def create_default_bank_account
self.build_bank_account
self.bank_account.save(:validate=>false)
# :validate=>false must be called on the bank_account's save. I made the mistake of trying to save the user. =(
end
This way, you can take the empty row creation out of the create action, which IMHO, should belong to the Model. You can then use the edit action to let users "create" the bank account entry. Using this, you only need a standard create action (e.g. generated by rails g scaffold_controller).
Update: I re-read your question after answering and found myself to be more confused. I assume you want to render a form where the user is not expected to enter the bank account immediately but edit it later on another page.
Address
validates_presence_of :phone, :on => :create, :if => proc { |u| u.creating_hotel? }
validates_presence_of :street, :phone, :on => :update
Contact
validates_presence_of :name, :email :on => :update
def creating_hotel?
addressable_type == 'Hotel'
end
The user sees the :street, :name, :email fields only after the hotel is created and :phone during the creation.