if statement for a model on a different show page - ruby-on-rails

I have two tables
create_table "book_rooms", force: :cascade do |t|
t.integer "room"
t.string "room_number"
end
and
create_table "rooms", force: :cascade do |t|
t.string "room_number"
end
in the rooms show page i want to display 'book_rooms.room_number' with same value with 'rooms.room_number' but I keep getting all book room objects printed out as an array in every room show page
rooms show page
<% #customer = BookRoom.all %>
<% if #customer[0].room_number = #room.room_number %>
<% #customer.each do |c| %>
<%= c.first_name %>
<% end %>
<% end %>
pls is there something I am not doing right? the if statement is meant to be false if the room_numbers dont tally but they still get printed out regardless! i am stuck

BookRoom.where(:room_number => #room.room_number)
This will fetch all the BookRoom with room_number from a specific Room (which is #room).
By the way I guess your association is not correct. There must be a has_many relation between BookRoom and Room.
The problem you're facing is, in your #customer variable you assign all BookRooms. Then based on this variable you created a loop. THus all the BookRoom are displaying.
Also, in your book_rooms schema there is no first_name.
EDIT
BUG: In your if condition you used the = operator instead of ==
<% #customer = BookRoom.all %>
<% #customer.each do |c| %>
<% if c.room_number == #room.room_number %>
<%= c.first_name %>
<% end %>
<% end %>

Related

Rails create multiple rows from one form

I have a rails app that has building and floors models
class Building < ApplicationRecord
has_many :floors
end
class Floor < ApplicationRecord
belongs_to :building
end
In my building form I want to ask the user how many floors the building has, and then when the building is created I want to add that many floors.
So the form would look like so:
<%= form_with(model: building, local: true) do |form| %>
<% if building.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(building.errors.count, "error") %> prohibited this building from being saved:</h2>
<ul>
<% building.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= form.label :name %>
<%= form.text_field :name %>
</div>
<div class="field">
<%= form.label :" How many floors does the building have" %>
<%= form.number :floors %> * not sure how to do this
</div>
<div class="actions">
<%= form.submit %>
</div>
<% end %>
Note I don't want the number of floors saved on the building model, it just creates the number of floors the user specified.
So if I created a building called "Walts Place" and said it has 10 floors it would create: Walts Place with id:1, and 10 floors with the building_id of 1.
Does that make sense?
Your help is greatly appreciated.
Update:
ActiveRecord::Schema.define(version: 2019_07_30_093037) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
create_table "buildings", force: :cascade do |t|
t.string "name"
t.float "distancetocondensors"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
end
create_table "floors", force: :cascade do |t|
t.bigint "building_id", null: false
t.string "name"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.index ["building_id"], name: "index_floors_on_building_id"
end
add_foreign_key "floors", "buildings"
end
you can modify it in your building controller in create action.
def create
#building = Building.new(building_params)
if #building.save
floors = params[:number].to_i
floors.times do
Floor.create(building: #building)
end
redirect_to building_path
else
redirect_to error
end
end
in your form add a field for number of floor without erb
<%= form_with(model: building, local: true) do |form| %>
<% if building.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(building.errors.count, "error") %> prohibited this building
from being saved:</h2>
<ul>
<% building.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= form.label :name %>
<%= form.text_field :name %>
</div>
<div class="field">
<label> How many floors does the building have</label>
<input type="number" name="number"/>
</div>
<div class="actions">
<%= form.submit %>
</div>
<% end %>
You can use nested attributes to help you here.
First, in your Building model add:
has_many :floors
accepts_nested_attributes_for :floors
Then in your BuildingController's create action do:
class BuildingController < ApplicationController
...
def create
floors_amount = params[:building][:floors] || 0
building_params = params.require(:building).permit(:name).merge({
# just fill floors array with empty hashes since `id` will be added automatically
floors_attributes: (1..floors_amount).to_a.fill({})
})
#building = Building.create(building_params)
if #buildnig.errors
render :new # show the form page with an error
else
redirect_to #building # or whenever you want to redirect
end
end
...
end
The advantage here is that it wraps the creation of building and floors into a transaction so if something goes wrong it will rollback all changes. I.e. there won't be a case where new Building is inserted into DB but floors didn't due to some error during their creation.
Another convenience here is that if some validation error appears either on building or on any of the floor then it will be set into building.errors. Means you can easily do render :new in the case of errors to display them.
Note:
I see that in your form view you access Building instance as building. So I'm not really sure how you pass it to this view.
In my example I saved building into #building variable so that in this view form you will have to access it as #building. I believe in your new action in BuildingController you should set it to #building as well:
class BuildingController < ApplicationController
...
def new
#building = Building.new
end
...
end
And in your view you will access it as #building then, not building.
Hope, that makes sense

Rails 4: child record ID is saved but not its attributes, using nested form with has_many through relationship

I have 3 models with a has_many through relationship: Food (eg: Chocolate), Sub (Chocolate food substitute), Joint (joint table).
Say #food = Food.find(1); The has_many through relationship allows me to do #subs = #food.subs which return all substitutes associated with #food. This work fine, however only the Sub id is saved and not its attributes which are :name and :description as you can see it returned nil when trying to save #food.subs in my create action in my controller:
=> #<ActiveRecord::Associations::CollectionProxy [#<Sub id: 28,name:nil,description:nil,created_at:
"2015-01-07 00:40:35", updated_at: "2015-01-07 00:40:35">]>
I guess the issue lies with my create action in my food controller and perhaps something to do with my nested form as well. I spent countless hours trying to figure this out I am so desperate to find an answer. I really do not know where to look anymore.
I am new to rails so thanks a lot for your help and your time, I really appreciate it. Please if possible adapt your answer to my beginner level :-) .
Down below are samples of my controller, form and relevant information.
Here are my models:
class Food < ActiveRecord::Base
has_many :joints
has_many :subs, :through => :joints
accepts_nested_attributes_for :subs
end
class Sub < ActiveRecord::Base
has_many :joints
has_many :foods, :through => :joints
accepts_nested_attributes_for :foods
end
class Joint < ActiveRecord::Base
belongs_to :food
belongs_to :sub
end
Here is my db-schema FYI:
create_table "foods", force: true do |t|
t.string "name"
t.text "description"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "joints", force: true do |t|
t.integer "food_id"
t.integer "sub_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "subs", force: true do |t|
t.string "name"
t.text "description"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
Here is my foods_controller:
def new
#food = Food.new
#sub = Sub.new
end
def create
#food = Food.new(food_params)
#food.subs.build(params[:subs])
#food.save
respond_to do |format|
if #food.save
format.html { redirect_to #food, notice: 'Food was successfully created.' }
format.json { render :show, status: :created, location: #food }
else
format.html { render :new }
format.json { render json: #food.errors, status: :unprocessable_entity }
end
end
end
private
def food_params
params.require(:food).permit(:name, :description, subs_attributes: [:name, :description])
end
end
Here is my views/foods/_form:
<%= form_for(#food) do |f| %>
<% if #food.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#food.errors.count, "error") %> prohibited this food from being saved:</h2>
<ul>
<% #food.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :name %><br>
<%= f.text_field :name %>
</div>
<div class="field">
<%= f.label :description %><br>
<%= f.text_area :description %>
</div>
<div>
<%= f.fields_for(#sub) do |sub| %>
<div class="field">
<%= sub.label :name %>
<%= sub.text_field :name %>
</div>
<div class="field">
<%= sub.label :description %>
<%= sub.text_area :description %>
</div>
<% end %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
My routes in case it helps:
resources :foods
resources :subs
resources :joints
root "foods#index"
Thank you very much !
Antoine.
In your new action:
def new
#food = Food.new
#food.subs.build
end
and in your view:
<%= f.fields_for :subs do |sub| %>
When you're passing directly an object, this object becomes the new form_builder's object - rails have no idea it is in any way connected with original object so it will result in different field names.
When you pass a symbol, rails will first try to find if your current object defines subs_attributes method. If so it will loop over subs association and build the fields for each associated model.
Reference here.
UPDATE - answer to comment:
Firstly - #subs is not a symbol, it is an instance variable. Symbols start with a colon like :subs. When fields_for receives an argument, it checks whether it is a symbol or object. In former case it search an object associated with form builder (f.object) to find out if it defines <passed_symbol>_attributes=. That way it knows that the model accepts nested attributes for this association so it can behave accordingly (the new form builder is created for each associated object with a correct name - <symbol>_attributes).
When object is passed, rails has no way of detecting if this is in ay way connected to the current object - you could have two associations for the same type of objects, or even it might have absolutely nothing to do with the original object. In that case fields_for acts like it was a nested form_for - resulting form builder will carry the model name of the object (f.object.class.model_name.singular)

I am developing an app in rails that requires retrieving the total number of votes per day

I am developing an app in rails that requires retrieving the total number of votes per day.
I have the following migrations,
class CreateVotes < ActiveRecord::Migration
def self.up
create_table :votes, :primary_key => :vote_id do |t|
t.string :client_id
t.integer :satlevel_id
t.integer :service_id
t.date "date", :default => Date.today
t.timestamps
end
end
end
class CreateSatlevels < ActiveRecord::Migration
def self.up
create_table :satlevels, :primary_key => :satlevel_id do |t|
t.string :name
t.timestamps
end
end
end
currently, i have the following in my controller.
class AdminController < ApplicationController
def index
render :layout => 'admin'
end
def forth
#votes = Vote.all
#satlevel = Satlevel.all
#result = Satlevel.joins(:votes)
#result2 = #result.find_by_sql("select name, date, count(*) as 'total_votes' from satlevels left join votes on satlevels.satlevel_id = votes.satlevel_id group by satlevels.satlevel_id ")
end
end
and this is what i have in my view,
<tr width = "100%">
<th>DATE</th>
<% #result2.each do |result| %>
<th><%= result.name%></th>
<% end%>
</tr>
<% #result2.each do |result| %>
<tr>
<td><%= result.date %></td>
<% #result2.each do |result| %>
<td><%= result.total_votes %></td>
<% end %>
<% end %>
</tr>
<tr>
This outputs the total number of votes for each day but instead of having one row for each date, each vote has its own row and date displayed together with the total votes.
I need help to output the count of all objects created in one day into a single row
Not entirely sure what you're asking here, but it looks like you're grouping by satlevel_id instead of on the date? From your view code it looks like you're wanting to group by date AND name?
Also, are you not following Rails conventions with your naming? Is your satlevels table's id actually satlevel_id or is it just id?
Making the assumptions that you're trying to count the number of occurrences for a name and a date AND you ARE actually using Rails conventions, here's how I would write the method:
def forth
#result = Satlevel.select('satlevels.name, votes.date, count(votes.*) as total_votes')
.joins(:votes)
.group('satlevels.name, votes.date')
.order('satlevels.name, votes.date')
end

Submit multiple model objects from one form with Rails

I've tried following this advice but I haven't succeeded yet in generating a form containing 3 objects of the same type under one submit button.
When I navigate to a page that should show a form containing fields for 3 objects (called elements in this example) I get the following error:
undefined method 'elements' for nil:NilClass
Any pointers would be much appreciated! My code is as follows:
app/controllers/elements_controller.rb
class ElementsController < ApplicationController
def index
#element_group = ElementGroup.new
render 'pages/index'
end
end
app/views/pages/home.html.erb
<%= render 'element_groups/form'%>
app/views/element_groups/_form.html.erb
<% form_for :element_group do |f|%>
## The error comes from this next line, as f.object is nil
<% f.object.elements.each do |element| %>
<% f.fields_for element do |element_form| %>
<%= element_form.text_field :content %>
<%= element_form.text_field :element_type %>
<%= element_form.text_field :subtype %>
<% end %>
<% end %>
<% end %>
app/models/element_group.rb
class ElementGroup
attr_accessor :elements
def elements
#elements = []
3.times do
#elements << Element.new
end
#elements
end
end
app/models/element.rb
class Element < ActiveRecord::Base
attr_accessible :element_type, :subtype, :content
end
db/schema.rb
create_table "elements", :force => true do |t|
t.string "element_type"
t.string "subtype"
t.string "content"
t.datetime "created_at"
t.datetime "updated_at"
end
Have you tried to change to <% form_for #element_group do |f|%> ?

is an instance variable in an action of a controller available for all the controllers view?

I am just trying to print the parameters that have been entered into my form.
Basically I create a new bet then I display the parameters:
MIGRATION
class CreateBets < ActiveRecord::Migration
def self.up
create_table :bets do |t|
t.integer :accepted ,:default => 0
t.integer :user_1_id #proposer
t.integer :user_2_id #receiver
t.integer :team_1_id #proposer's team
t.integer :team_2_id #receiver's team
t.integer :game_id
t.integer :winner
t.integer :amount
t.timestamps
end
end
def self.down
drop_table :bets
end
end
CONTROLLER
bets_controller.erb
class BetsController < ApplicationController
def index
redirect_to new_bet_path
end
def new
#b=Bet.new
end
def create
#points=params[:points]
#winner=params[:winner]
end
end
VIEWS
New.erb
<% facebook_form_for Bet.new do |f| %>
<%= f.text_field :amount, :label=>"points" %>
<%= f.text_field :winner, :label=>"WinningTeam" %>
<%= f.buttons "Bet" %>
<% end %>
create.erb
points:<%= #points %>
<br>
winner:<%= #winner %>
I tried to make this code work with instance variables but it didn't work either. Where is the problem?
Thank you.
I think that params[:winner] and params[:point] is empty hash. Try adding this to your create.erb:
params: <%= params.inspect %>
It will display your params hash, so you will see how to get to it.
Another hint, why you are creating new object in new action and then in form you are doing it again? So:
<% facebook_form_for #b do |f| %>
And another thing, it is really good to keep naming conventions, so don't create #b object, but #bet.
In create action you should have line like this:
#bet = Bet.new(params[:bet])
And in view:
<p>
points:<%= #bet.points %>
</p>
<p>
winner:<%= #bet.winner %>
</p>
If you use <br> it's better to use <br/>.
Your index action is totaly useless. It would be better if you would move all behaviour from new action to index and remove new action completly.
As klew pointed, for me it seems that you're getting empty params[:winner]and params[:point]. You can make sure that of what you're getting by taking a look at your servers log.
You will see a line like
Processing BetsController#create (for 127.0.0.1 at 2010-04-11 20:56:51) [POST]
Parameters: {"your"=>"parameters", "should"=>"apper in this hash"}

Resources