I'm trying to submit a form for my rails app but I'm getting the error in the title and I'm not entirely sure how to fix it. Category is my foreign key.
= form_for #menu_price do |f|
- if #menu_price.errors.any?
#error_explanation
h2 = "#{pluralize(#menu_price.errors.count, "error")} prohibited this menu_price from being saved:"
ul
- #menu_price.errors.full_messages.each do |message|
li = message
.form-group
= f.label :category
= f.select :category, options_for_select(#categories.map{ |c| [c.name] })
.form-group
= f.label :price
= f.number_field :price
.form-group
= f.label :description
= f.text_field :description
.form-group
= f.label :serves
= f.text_field :serves
= f.submit
= link_to 'Back', menu_prices_path, class:'button'
My models look like this
class Category < ActiveRecord::Base
has_many :menu_prices
validates :category, :presence => true
end
***********Updated***********
class CreateMenuPrices < ActiveRecord::Migration
def change
create_table :menu_prices do |t|
t.text :description, :null => false
t.decimal :price , :default => nil , :null => true
t.string :serves, :default => nil , :null => true
t.integer :small , :default => nil , :null => true
t.integer :regular, :default => nil , :null => true
t.integer :large, :default => nil , :null => true
t.integer :party, :default => nil, :null => true
t.timestamps null: false
end
add_reference :menu_prices, :categories
end
end
I understand that it wants a foreign key but I'm not sure how to go about submitting the foreign key in the form. Any help would be greatly appreciated.
******UPDATE******
My schema.rb is below
create_table "categories", force: :cascade do |t|
t.string "name"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "menu_prices", force: :cascade do |t|
t.text "description", null: false
t.decimal "price"
t.string "serves"
t.integer "small"
t.integer "regular"
t.integer "large"
t.integer "party"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "categories_id"
end
end
Since you're actually passing only category_id from view (and not whole Category object), instead of
f.label :category
and
f.select :category
you should have:
f.label :category_id
and
f.select :category_id
You should also make sure category_id column is present in menu_prices table.
Related
I want to save a record to a Bookings table that has foreign keys from Schedules and Users table.
Here is the schema:
create_table "bookings", force: :cascade do |t|
t.integer "seats"
t.integer "base_price"
t.integer "total_price"
t.string "status"
t.integer "schedules_id", null: false
t.integer "users_id", null: false
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.index ["schedules_id"], name: "index_bookings_on_schedules_id"
t.index ["users_id"], name: "index_bookings_on_users_id"
end
create_table "schedules", force: :cascade do |t|
t.string "departure", null: false
t.string "destination", null: false
t.integer "seats_available", null: false
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.integer "price"
t.datetime "date_time"
end
create_table "users", force: :cascade do |t|
t.string "email", null: false
t.string "password_digest", null: false
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.string "firstname", null: false
t.string "lastname", null: false
end
Schedule and User has_many :bookings and Booking belongs_to :schedules and :users.
My view in bookings/new.html.erb
<%= form_for(#book, url: booking_path, local: true) do |f| %>
<% #books.each do |data| %>
<%= data.departure %>
<%= data.destination %>
<%= data.formatted_date_time %>
<%= data.seats_available %>
<%= data.price %>
<%= f.hidden_field :base_price, value: data.price %>
<%= f.hidden_field :seats %>
<%= f.hidden_field :total_price %>
<%= f.submit "Book" %>
<% end %>
<% end %>
I'm not sure this is the best way to do it but this is my attempt. Assume the hidden fields has a way to get the data, because I cut out the code that does it since I can see the params being passed in the Command Prompt.
My routes:
get 'booking', to: 'bookings#new'
post 'booking', to: 'bookings#create'
My BookingsController:
def new
#books = Schedule.where(id: params[:book_id])
#book = Booking.new
end
def create
#book = Booking.new(booking_params)
if #book.save
flash[:success] = 'success'
redirect_to root_path
end
end
private
def booking_params
params.require(:booking).permit(:base_price, :seats, :total_price)
end
In the command prompt it does display the parameters { "booking"=>{"base_price"=>"80", "seats"=>"2", "total_price"=>"160"}, "commit"=>"Book"}. The problem is that after that it now loads bookings/create.html.erb without saving the params. It somehow doesn't do the if #book.save part. Also I don't know how I can put the foreign keys or the :status variable or do I even need to. I appreciate the help!
I have a table called sublet post which has these columns and there is a reference column to the property table.
create_table "sublet_posts", force: :cascade do |t|
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "property_id"
t.index ["property_id"], name: "index_sublet_posts_on_property_id"
Property table
create_table "properties", force: :cascade do |t|
t.string "address"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
In the sublet post form view
<div class="field">
<%= collection_select(:sublet_post, :property_id, #properties, :id, :address, prompt: true) %>
<%= form.hidden_field :property_id, value: params[:sublet_post][:property_id] %>
</div>
In the form view, I am using the address as the selections and if a user clicks on an address, I would like the id to be stored in the for the value of the hidden value :property_id. I would like to do something similar to the code above.
You can add an id to both elements and catch the change event.
The html will be so:
<div class="field">
<%= collection_select(:sublet_post, :property_id, #properties, :id, :address, prompt: true, id: 'the_collection') %>
<%= form.hidden_field :property_id, value: params[:sublet_post][:property_id], id: 'the_field'%>
</div>
And the javascript, if you are using jQuery :
$(document).on('change', '#the_collection', function(event) {
var element = $(event.target);
element.siblings('#the_field').val(element.val());
});
https://api.jquery.com/siblings/
I have 3 tables called pins (posts), genres (categories) and genre_pin (many to many between pins and genres because pins can have many genres).
I am trying to build the create form, which will allow the user to select as many genres as they want on a pin and save / create. The create works just fine without error, but it is not saving any relationship records to the genre_pin table. I'm pretty sure I may be missing something very obvious here.
I am using the terms 'pins' and 'genres', but you can think of these as the same as 'posts' and 'categories'.
Pin Model
class Pin < ActiveRecord::Base
belongs_to :user
belongs_to :type
has_many :replies
has_many :genre_pins
has_many :genres, :through => :genre_pins
accepts_nested_attributes_for :genres, allow_destroy: true, reject_if: proc { |genre| genre[:id].blank? }
validates :user_id, presence: true
validates :type_id, presence: true
validates :title, presence: true
validates :description, presence: true
end
Genre Model
class Genre < ActiveRecord::Base
has_many :genre_pins
has_many :pins, :through => :genre_pins
validates :title, presence: true
end
GenrePin Model
class GenrePin < ActiveRecord::Base
belongs_to :pin
belongs_to :genre
validates_uniqueness_of :pin_id, :scope => :genre_id
end
Next, in my pin#new view, I have the following form:
Pin New View
<%= form_for :pin, url: pins_path do |f| %>
<div class="small-12 columns">
<%= f.label :title %>
<%= f.text_field :title %>
</div>
<div class="small-12 columns">
<%= f.label :description %>
<%= f.text_area :description, :rows => 10 %>
</div>
<div class="small-12 columns">
<%= f.label :type %>
<%= f.collection_select :type_id, Type.order(:title), :id, :title, include_blank: false %>
</div>
<div class="small-12 columns">
<%= f.label :genres %>
<%= f.collection_select :genre_ids, Genre.order(:title), :id, :title, {}, { :multiple => true } %>
</div>
<div class="small-12 columns">
<%= f.submit "Create Pin", :class => "button" %>
</div>
<% end %>
The view works fine and gets me the available genres from the genres table. However, when I go to save the form, the record (pin) is created, but the relationship with the genres is not. What am I missing here? No errors are thrown, it's just that nothing happens. I am assuming Rails should be creating these PinGenre records through a pins association with genre.
Pin Controller (create)
def create
#pin = Pin.new(pin_params)
#pin.user_id = current_user.id
#pin.save
if #pin.save
flash[:success] = "Pin successfully created"
redirect_to #pin
else
flash[:warning] = #pin.errors.full_messages.to_sentence
redirect_to :action => "new"
end
end
private
def pin_params
params.require(:pin).permit(:title, :description, :type_id, :genre_ids)
end
Are there further steps I need to make here? Do the records need to be explicitly created by myself?
Thanks for your help and patience. I hope I've made this read clearly.
Michael.
Schema.rb
ActiveRecord::Schema.define(version: 0) do
create_table "genre_pins", force: true do |t|
t.integer "pin_id"
t.integer "genre_id"
end
create_table "genres", force: true do |t|
t.string "title", null: false
end
create_table "pins", force: true do |t|
t.integer "user_id", null: false
t.string "title", limit: 160, null: false
t.text "description", null: false
t.decimal "latitude", precision: 10, scale: 8
t.decimal "longitude", precision: 11, scale: 8
t.datetime "created_at"
t.datetime "updated_at"
t.datetime "deleted_at"
t.integer "type_id", null: false
end
create_table "profiles", force: true do |t|
t.integer "user_id", null: false
t.string "first_name", null: false
t.string "last_name", null: false
t.string "gender"
t.string "email"
t.text "bio"
t.decimal "latitude", precision: 10, scale: 8
t.decimal "longitude", precision: 11, scale: 8
t.string "image", limit: 2000
t.datetime "updated_at"
t.datetime "created_at"
t.datetime "deleted_at"
end
create_table "replies", force: true do |t|
t.integer "pin_id", null: false
t.integer "user_id", null: false
t.text "reply", null: false
t.datetime "updated_at"
t.datetime "created_at"
t.datetime "deleted_at"
end
create_table "saves", force: true do |t|
t.integer "pin_id", null: false
t.integer "user_id", null: false
t.datetime "updated_at"
t.datetime "created_at"
t.datetime "deleted_at"
end
create_table "settings", force: true do |t|
t.integer "user_id", null: false
t.boolean "show_email", null: false
t.boolean "show_telephone", null: false
t.integer "timezone", null: false
t.datetime "updated_at"
t.datetime "created_at"
t.datetime "deleted_at"
end
create_table "types", force: true do |t|
t.string "title", null: false
end
create_table "users", force: true do |t|
t.string "provider", limit: 45, null: false
t.string "provider_id", limit: 45, null: false
t.string "oauth_token", limit: 1000
t.datetime "oauth_expires_at"
t.datetime "updated_at"
t.datetime "created_at"
t.datetime "deleted_at"
end
end
Generated View Source
<form accept-charset="UTF-8" action="/pins" method="post"><div style="margin:0;padding:0;display:inline"><input name="utf8" type="hidden" value="✓" /><input name="authenticity_token" type="hidden" value="3VO3kVR/62JFf6dJs+yyPTPvYJb3fsUSLRFljSE0Jdk=" /></div>
<div class="small-12 columns">
<label for="pin_title">Title</label>
<input id="pin_title" name="pin[title]" type="text" />
</div>
<div class="small-12 columns">
<label for="pin_description">Description</label>
<textarea id="pin_description" name="pin[description]" rows="10">
</textarea>
</div>
<div class="small-12 columns">
<label for="pin_type">Type</label>
<select id="pin_type_id" name="pin[type_id]"><option value="2">Available</option>
<option value="1">Wanted</option></select>
</div>
<div class="small-12 columns">
<label for="pin_genres">Genres</label>
<input name="pin[genre_ids][]" type="hidden" value="" /><select id="pin_genre_ids" multiple="multiple" name="pin[genre_ids][]"><option value="5">Ambient</option>
<option value="4">Electronic</option>
<option value="2">Indie</option>
<option value="3">Jazz</option>
<option value="6">Metal</option>
<option value="1">Rock</option></select>
</div>
<div class="small-12 columns">
<input class="button" name="commit" type="submit" value="Create Pin" />
</div>
</form>
You need to tell your controller that 'genre_ids` is expected to be an array:
params.require(:pin).permit(:title, :description, :type_id, genre_ids: [])
However I expect you will get another error (unknown attribute gener_ids). Let me know if that happen.
I have a form with :
<%= f.collection_select :carburants_id_eq_all, Carburant.order(:name), :id, :name, {}, { multiple: true } %>
When I select only 1 Carburant, it's render me the result normaly, but if I select more than 1 Carburant, the result is empty.
Here's my form in 'index.html.erb' :
<%= search_form_for #search do |f| %>
<%= f.label :title_cont, "Name contains" %>
<%= f.text_field :title_cont %>
<%= f.collection_select :carburants_id_eq_all, Carburant.order(:name), :id, :name, {}, { multiple: true } %>
<%= f.submit "Search" %>
<% end %>
My index action in my 'post_controller.rb':
def index
#search = Post.search(params[:q])
#posts = #search.result(distinct: true)
end
My post.rb, carburant.rb and category.rb model :
class Category < ActiveRecord::Base
attr_accessible :carburant_id, :post_id
belongs_to :carburant
belongs_to :post
end
class Post < ActiveRecord::Base
attr_accessible :content, :title, :carburant_ids
has_many :categories
has_many :carburants, through: :categories
end
class Carburant < ActiveRecord::Base
attr_accessible :name
has_many :categories
has_many :posts, through: :categories
end
My DB shema :
ActiveRecord::Schema.define(:version => 20130114004613) do
create_table "carburants", :force => true do |t|
t.string "name", :limit => nil
t.datetime "created_at"
t.datetime "updated_at"
end
create_table "categories", :force => true do |t|
t.integer "post_id"
t.integer "carburant_id"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
create_table "posts", :force => true do |t|
t.string "title"
t.text "content"
t.datetime "created_at"
t.datetime "updated_at"
end
create_table "recherches", :force => true do |t|
t.string "title"
t.integer "carburant_id"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
end
Thank you by advance.
EDIT 1:
I tried replacing :carburants_id_eq_all by :carburants_id_eq_any in my form just to test, and it work perfecly with the EQ_ANY predicate, but still not with the EQ_ALL.
I have a rails model with a hashed password field in it (surprise, surprise), which after some manipulation, is 40 characters long. I generate a user in script/console and it appears as follows:
#<User id: 1, firstname: "true", lastname: "false", username: "chaines51", hashed_password: "2Gr0GWvPunB3x5jomRTSTZJRIelC2RW103d7f3db">
I then run user_instance.save, which returns true, and the user then looks like this:
#<User id: 1, firstname: "true", lastname: "false", username: "chaines51", hashed_password: "103d7f3db">
Any idea what is happening to the other 30+ characters? I changed the field in the migration from string to text, but it still gets truncated
EDIT: The model code is:
require 'digest/sha1'
class User < ActiveRecord::Base
validates_presence_of :username, :password, :password_confirmation, :firstname, :lastname
validates_length_of :username, :within => 3..40
validates_length_of :password, :within => 5..40
validates_uniqueness_of :username
validates_confirmation_of :password
belongs_to :school
attr_protected :id, :salt
attr_accessor :password, :password_confirmation
def self.random_string(len)
#generate a random salt consisting of digits and letters.
chars = ("a".."z").to_a + ("A".."Z").to_a + ("0".."9").to_a
salt = ""
1.upto(len) { |i| salt << chars[rand(chars.size-1)] }
return salt
end
def password=(pass)
#password=pass
#salt = User.random_string(40-pass.length)
self.hashed_password = User.encrypt(#password, #salt)
end
def self.encrypt(pass, salt)
hash = Digest::SHA1.hexdigest(pass+salt)
hash.slice!(0..(40-pass.length-1))
hash = salt+hash;
end
def self.checkhash(pass, hash)
salt = hash.slice!(0..40-pass.length-1)
rehash = User.encrypt(pass, salt)
return rehash == (salt+hash)
end
def self.authenticate(login, pass)
u = User.find_by_username(login)
return nil if u.nil?
return u if User.checkhash(pass, u.hashed_password)
nil
end
end
and the db/schema.rb is:
ActiveRecord::Schema.define(:version => 20100127034504) do
create_table "categories", :force => true do |t|
t.string "title"
end
create_table "questions", :force => true do |t|
t.string "question"
t.string "a"
t.string "b"
t.string "c"
t.string "d"
t.string "e"
t.datetime "created_at"
t.datetime "updated_at"
end
create_table "questions_quizzes", :id => false, :force => true do |t|
t.integer "app_id"
t.integer "category_id"
t.datetime "created_at"
t.datetime "updated_at"
end
create_table "quizzes", :force => true do |t|
t.string "title"
t.integer "category_id"
end
create_table "schools", :force => true do |t|
t.string "name"
t.integer "coach_id"
end
create_table "users", :force => true do |t|
t.string "firstname", :null => false
t.string "lastname", :null => false
t.string "username", :null => false
t.boolean "needs_pass", :default => false
t.integer "school_id"
t.datetime "created_at"
t.datetime "updated_at"
t.boolean "confirmed", :default => false
t.text "hashed_password"
end
end
Showing the model code, and the table info form db/schema.rb, would be really helpful. Right off, I can tell you that a string column will hold up to 255 characters without a problem, so there might be something else at fault. If something is restricting, it will most likely show itself in one of the two places I named above.