I have a pupils model and a groups model. When adding a new pupil I have a collection_select box with :multiple=> true so that the pupil can be put into several groups.
<div class="field">
<%= f.label "All Groups" %><br />
<%= collection_select(:groups, :id, #all_groups,
:id, :name, {},
{:multiple => true}) %>
</div>
I have an edit pupil form that when loaded selects the groups the pupil was previously assigned so that they can be changed if needs be so has the extra bit in {} in the collection select options;
<div class="field">
<%= f.label "All Groups" %><br />
<%= collection_select(:groups, :id, #all_groups,
:id, :name, {selected: #previous_selection},
{:multiple => true}) %>
</div>
the #previous_selection is set in the pupils_controller;
#previous_selection = Array.new
#pupil.groups.each do |pg|
#previous_selection.push(pg.id)
end
This is in the def edit block so only setup for the edit page.
Here is the PupilsController;
class PupilsController < ApplicationController
before_action :set_pupil, only: [:show, :edit, :update, :destroy]
def index
#pupils = Pupil.all
end
def show
#pupil_groups = #pupil.groups
end
def new
#pupil = Pupil.new
#all_groups = set_pupil_list
end
def edit
#all_groups = set_pupil_list
#previous_selection = Array.new
#pupil.groups.each do |pg|
#previous_selection.push(pg.id)
end
end
def create
#pupil = Pupil.new(pupil_params)
clean_select_multiple_params
logger.debug "The groups parameter contains: #{params[:groups][:id]}"
selected_groups = Group.find(params[:groups][:id])
#pupil.groups = selected_groups
respond_to do |format|
if #pupil.save
format.html { redirect_to #pupil, notice: 'Pupil was successfully created.' }
format.json { render action: 'show', status: :created, location: #pupil }
else
format.html { render action: 'new' }
format.json { render json: #pupil.errors, status: :unprocessable_entity }
end
end
end
def update
respond_to do |format|
if #pupil.update(pupil_params)
clean_select_multiple_params
selected_groups = Group.find(params[:groups][:id])
#pupil.groups = selected_groups
format.html { redirect_to #pupil, notice: 'Pupil was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: 'edit' }
format.json { render json: #pupil.errors, status: :unprocessable_entity }
end
end
end
def destroy
#pupil.destroy
respond_to do |format|
format.html { redirect_to pupils_url }
format.json { head :no_content }
end
end
def full_name
#fn = #pupil.given_name
#sn = #pupil.surname
#full_name = #fn + #sn
end
private
def set_pupil
#pupil = Pupil.find(params[:id])
end
def set_pupil_list
Group.all
end
def clean_select_multiple_params hash = params
hash.each do |k, v|
case v
when Array then v.reject!(&:blank?)
when Hash then clean_select_multiple_params(v)
end
end
end
def pupil_params
params.require(:pupil).permit(:given_name, :surname, :date_of_birth, :gender, :ethnicity)
end
end
When the new pupil page is requested the _form.html.erb file is used that has the {selected: #previous_selection} argument in it that has not been set up by def new in the pupils_controller but there is not a error message about #previous_selection not being initialized.
I would expect an error but am not getting one but do not understand why. Could someone please explain? I am new to programming in general so sorry if I am using the wrong terminolog.
Thank you
Leon
#previous_selection variable is nil, and hence in the view none of collection items will be selected. It is not necessary to initialize a variable to nil, rails does that.
Related
I use devise gem for authentication. I generated a scaffold for model M. I would like to update the created_by field with the user id from the login page. How do I achieve this?
I have 2 fields in the model F1 and F2.
The form that scaffold creates shows input for users to enter values for F1 and F2. How do I update the value for created_by field using the current_user from devise? Because the create action seems to be entering only the fields from the form.
<%= form_with(model: M, local: true) do |form| %>
<% if M.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(M.errors.count, "error") %> prohibited this movie from being saved:</h2>
<ul>
<% M.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= form.label :F1 %>
<%= form.text_field :F1 %>
</div>
<div class="field">
<%= form.label :F2 %>
<%= form.text_field :F2 %>
</div>
<div class="actions">
<%= form.submit %>
</div>
<% end %>
How to I update the model with current_user value in the above form without exposing that field to the user?
This is my controller:
class MsController < ApplicationController
before_action :set_M, only: [:show, :edit, :update, :destroy]
# GET /Ms
# GET /Ms.json
def index
#Ms = M.all
#categories = #Ms.uniq.pluck(:category)
#Ms_by_category = Hash.new
#categories.each do |category|
#Ms_by_category[category] = M.where(:category => category)
end
end
# GET /Ms/1
# GET /Ms/1.json
def show
end
# GET /Ms/new
def new
#M = M.new
end
# GET /Ms/1/edit
def edit
end
# POST /Ms
# POST /Ms.json
def create
#M = M.new(M_params)
respond_to do |format|
if #M.save
format.html { redirect_to #M, notice: 'M was successfully created.' }
format.json { render :show, status: :created, location: #M }
else
format.html { render :new }
format.json { render json: #M.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /Ms/1
# PATCH/PUT /Ms/1.json
def update
respond_to do |format|
if #M.update(M_params)
format.html { redirect_to #M, notice: 'M was successfully updated.' }
format.json { render :show, status: :ok, location: #M }
else
format.html { render :edit }
format.json { render json: #M.errors, status: :unprocessable_entity }
end
end
end
# DELETE /Ms/1
# DELETE /Ms/1.json
def destroy
#M.destroy
respond_to do |format|
format.html { redirect_to Ms_url, notice: 'M was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_M
#M = M.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def M_params
params.require(:M).permit(:title, :category, :rating)
end
end
So simple in creating action change your method, for example, you just need to create the client
before_action :authenticate_user!
def create
#client = Client.new(name: params[:name], address: params[:address],created_by: current_user.email )
if #client.save
redirect_to #client
else
render 'new'
end
end
There should be a field like created_by exist in the table.
You need to add users reference to M model and add associations. created_by is not the best name for it. Let imagine that M is abbreviation for Music. In this case you need to create a migration
add_reference :musics, :user
Add to the Music model
belongs_to :user
And to the User model
has_many :musics
And change in the controller
def new
#music = current_user.musics.new
end
def create
#music = current_user.musics.new(M_params)
respond_to do |format|
if #music.save
format.html { redirect_to #music, notice: 'Music was successfully created.' }
format.json { render :show, status: :created, location: #music }
else
format.html { render :new }
format.json { render json: #music.errors, status: :unprocessable_entity }
end
end
end
sorry for this question but I'm struggling with this issue for hours now and can't find the answer anywhere.
Here is the thing, I have a rails app with "Reservation" and "Space" models with the following relations:
class Reservation < ActiveRecord::Base
belongs_to :space
belongs_to :user
end
class Space < ActiveRecord::Base
belongs_to :condo
has_many :reservations
end
When the user creates a new Reservation, in the form he gets to choose from a dropdown (f.select) the spaces available for him. The f.select in the form look like this:
<div class="field">
<%= #user_spaces = current_user.condo.spaces
f.select :space_id,
options_from_collection_for_select(#user_spaces, :id, :name), :prompt => "Select space"
%>
</div>
That select it supose to assign a value to the key "space_id" in the Reservation that is being created (column's table is created). But when I check the last reservation in Rails console, space_id value is "nil". What am I doing wrong?
Thank you very much for your help
Reservation controller file:
class ReservationsController < ApplicationController
before_action :set_reservation, only: [:show, :edit, :update, :destroy]
# GET /reservations
# GET /reservations.json
def index
#reservations = Reservation.all
end
# GET /reservations/1
# GET /reservations/1.json
def show
end
# GET /reservations/new
def new
#reservation = Reservation.new
end
# GET /reservations/1/edit
def edit
end
# POST /reservations
# POST /reservations.json
def create
#reservation = Reservation.new(reservation_params)
#user = current_user.id
#reservation.user_id = #user
respond_to do |format|
if #reservation.save
format.html { redirect_to #reservation, notice: 'Reservation was successfully created.' }
format.json { render :show, status: :created, location: #reservation }
else
format.html { render :new }
format.json { render json: #reservation.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /reservations/1
# PATCH/PUT /reservations/1.json
def update
respond_to do |format|
if #reservation.update(reservation_params)
format.html { redirect_to #reservation, notice: 'Reservation was successfully updated.' }
format.json { render :show, status: :ok, location: #reservation }
else
format.html { render :edit }
format.json { render json: #reservation.errors, status: :unprocessable_entity }
end
end
end
# DELETE /reservations/1
# DELETE /reservations/1.json
def destroy
#reservation.destroy
respond_to do |format|
format.html { redirect_to reservations_url, notice: 'Reservation was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_reservation
#reservation = Reservation.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def reservation_params
params.require(:reservation).permit(:eventdate)
end
end
Space controller file:
class SpacesController < ApplicationController
before_action :set_space, only: [:show, :edit, :update, :destroy]
# GET /spaces
# GET /spaces.json
def index
#spaces = Space.all
end
# GET /spaces/1
# GET /spaces/1.json
def show
end
# GET /spaces/new
def new
#space = Space.new
end
# GET /spaces/1/edit
def edit
end
# POST /spaces
# POST /spaces.json
def create
#space = Space.new(space_params)
respond_to do |format|
if #space.save
format.html { redirect_to #space, notice: 'Space was successfully created.' }
format.json { render :show, status: :created, location: #space }
else
format.html { render :new }
format.json { render json: #space.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /spaces/1
# PATCH/PUT /spaces/1.json
def update
respond_to do |format|
if #space.update(space_params)
format.html { redirect_to #space, notice: 'Space was successfully updated.' }
format.json { render :show, status: :ok, location: #space }
else
format.html { render :edit }
format.json { render json: #space.errors, status: :unprocessable_entity }
end
end
end
# DELETE /spaces/1
# DELETE /spaces/1.json
def destroy
#space.destroy
respond_to do |format|
format.html { redirect_to spaces_url, notice: 'Space was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_space
#space = Space.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def space_params
params.require(:space).permit(:name)
end
end
And full Reservation Form:
<%= form_for(#reservation) do |f| %>
<% if #reservation.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#reservation.errors.count, "error") %> prohibited this reservation from being saved:</h2>
<ul>
<% #reservation.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :eventdate %><br>
<%= f.date_select :eventdate %>
</div>
<div class="field">
<%= #user = current_user.condo.spaces
f.select :space_id,
options_from_collection_for_select(#user, :id, :name), :prompt => "Select space"
%>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
pretty sure you need to permit the space_id attribute in your strong params.
def reservation_params
params.require(:reservation).permit(:eventdate, :space_id)
end
whats happening is that when you go to create a reservation, youre passing in set of params, that is the output of reservation_params
#reservation = Reservation.new(reservation_params)
if space_id is not being permitted in your strong params, then it will be nil when created.
if this is not the issue, can you post what params are getting to the server, and what the output of reservation_params are.
I'm not sure if this is even possible using Carrierwave, I'm still learning my way around Ruby and Rails so bear with me.
I have a simple form to record observations. Each observation has data that can be recorded against it and I store this in a JSONB column within the observation (I will eventually store multiple sets of data against an observation). I want to be able to upload an image through Carrierwave and store it with the data within the JSONB column rather than saving it to its own column. So my saved data for this column would be like this for example...
{
"ph":"",
"ecoli":"",
"nitri":"Less than 0.5",
"oxygen":"",
"clarity":"bottom visible",
"nitrates":"Less than 0.5",
"conditions":[
"Wildlife Death",
"Shoreline Alterations",
"Water Quality"
],
"observed_on":"2015-06-21T04:45",
"invasive_species":[
"Phragmites",
"Loosestrife",
"Dog-Strangling Vine"
],
"phosphates_threshold":"less than 0.2",
"image":[
"url": "the/url",
"thumbnail: "the/thumbnail/url",
"medium":"the/thumbnail/url"
.....
]
}
Some of the supporting code for reference...
observation.rb
class Observation < ActiveRecord::Base
belongs_to :user
has_many :comments
serialize :observation_data, HashSerializer
store_accessor :observation_data
end
observation_data.rb - tableless model
class ObservationData < ActiveRecord::Base
belongs_to :observation
mount_uploader :image, ImageUploader
end
_form.html.erb
<%= form_for #observation do |f| -%>
...Other form items
<fieldset>
<legend>Observation data</legend>
<%= render "observation_data", :f => f %>
</fieldset>
<div class="actions">
<%= f.submit "Submit", class: "button" %>
</div>
<% end %>
_observation_data.html.erb
<%= f.fields_for :observation_data, OpenStruct.new(#observation.observation_data) do |o| %>
...Other form items
<div class="field">
<%= o.label :image, "Upload an image" %>
<%= o.file_field :image %>
</div>
...Other form items
<% end %>
observations_controller.rb
class ObservationsController < ApplicationController
before_action :set_observation, only: [:show, :edit, :update, :destroy]
before_action :authenticate_user!
def index
#observations = Observation.all
#user = current_user.id
end
def show
#observations = Observation.find_by(id: params[:id])
#observation_data = #observation.observation_data
#comments = #observation.comments.all
#comment = #observation.comments.build
#user = User.find_by(id: #observation.user_id)
end
def new
#observation = Observation.new
end
def edit
end
def create
#observation = Observation.new(observation_params)
#observation.user_id = current_user.id
respond_to do |format|
if #observation.save
format.html { redirect_to #observation, notice: 'Observation was successfully created.' }
format.json { render action: 'show', status: :created, location: #idea }
else
format.html { render action: 'new' }
format.json { render json: #observation.errors, status: :unprocessable_entity }
end
end
end
def update
respond_to do |format|
if #observation.update(observation_params)
format.html { redirect_to #observation, notice: 'Observation was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: 'edit' }
format.json { render json: #observation.errors, status: :unprocessable_entity }
end
end
end
def destroy
#observation.destroy
respond_to do |format|
format.html { redirect_to root_url }
format.json { head :no_content }
end
end
private
def set_observation
#observation = Observation.find(params[:id])
end
def observation_params
params.require(:observation).permit(:user_id, :lat, :lng, :name, :description, :comment, observation_data: [:observed_on, :image, :ph, :oxygen, :ecoli, :phosphates_threshold, :clarity, :nitri, :nitrates, wildlife: [], conditions: [], invasive_species: []])
end
end
The problem for me is mount_uploader :image, ImageUploader is always looking for an :image column, how can I merge the Carrierwave response this with JSON in another column? Is it even possible?
I am having an isuue. I am creating a search form in my form. The form has restaurant name, city, and state.
Looks like this:
<%= form_tag(restaurants_path, :method => "get", id: "search-form") do %>
<%= label_tag(:restaurant_name) %>
<%= text_field_tag :restaurant_name, params[:restaurant_name] %> <br />
<%= label_tag(:city, "Restaurant City") %>
<%= text_field_tag :city, params[:city] %> <br />
<%= label_tag(:state, "Restaurant State") %>
<%= text_field_tag :state, params[:state] %> <br />
<%= submit_tag "Search", :name => nil %>
<% end %>
Now I am trying to get information for a part restaurant name/location.
I have seen that if my form is coded properly, which it is you can do something like:
Restaurant Controller:
class RestaurantsController < ApplicationController
before_action :set_restaurant, only: [:show, :edit, :update, :destroy, :search]
# GET /restaurants
# GET /restaurants.json
def index
constraints = Hash.new
constraints[:restaurant_name] = params[:restaurant_name]
constraints[:city] = params[:city]
if params[:restaurant_name] && params[:city]
##restaurants = Restaurant.search(params[:restaurant_name]).order('restaurant_name desc').paginate(:per_page => 5, :page => params[:page])
#restaurants = Restaurant.where(params).order('restaurant_name desc').paginate(:per_page => 5, :page => params[:page])
else
#restaurants = Restaurant.order('restaurant_name desc').paginate(:per_page => 5, :page => params[:page])
end
end
# GET /restaurants/1
# GET /restaurants/1.json
def show
end
# GET /restaurants/new
def new
#restaurant = Restaurant.new
end
# GET /restaurants/1/edit
def edit
end
# POST /restaurants
# POST /restaurants.json
def create
#restaurant = Restaurant.new(restaurant_params)
respond_to do |format|
if #restaurant.save!
session[:page] = 0
format.html { redirect_to restaurants_url, notice: 'Restaurant was successfully created.' }
format.json { head :no_content }
else
format.html { render :new }
format.json { render json: #restaurant.errors, status: :unprocessable_entity }
end
end
end
# GET /restaurants/1/search
# GET /restaurants/1.json
def gotosearch
end
def self.search
Restaurant.where("restaurant_name like ? AND city like ? ", params[:restaurant_name], params[:city])
end
# PATCH/PUT /restaurants/1
# PATCH/PUT /restaurants/1.json
def update
respond_to do |format|
if #restaurant.update(restaurant_params)
format.html { redirect_to #restaurant, notice: 'Restaurant was successfully updated.' }
format.json { render :show, status: :ok, location: #restaurant }
else
format.html { render :edit }
format.json { render json: #restaurant.errors, status: :unprocessable_entity }
end
end
end
# DELETE /restaurants/1
# DELETE /restaurants/1.json
def destroy
#restaurant.destroy
respond_to do |format|
format.html { redirect_to restaurants_url, notice: 'Restaurant was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_restaurant
#restaurant = Restaurant.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def restaurant_params
params.require(:restaurant).permit(:restaurant_name, :street, :city, :state, :zip, :split_the_check, :dont_split_the_check)
end
end
The problem is on this line:
#restaurants = Restaurant.where(params).order('restaurant_name desc').paginate(:per_page => 5, :page => params[:page])
You are searching with a variable called params, which holds all the parameters for the request. You need to do something more specific like this:
#restaurants = Restaurant.where(params[:restaurant_name]).order('restaurant_name desc').paginate(:per_page => 5, :page => params[:page])
Or you can search by constraints[:restaurant_name] since you're already declaring that variable.
And if you're searching based on multiple attributes you can do this:
#restaurants = Restautanr.where("restaurant_name = ? OR name = ? OR state = ?", params[:restaurant_name], params[:city], params[:state])
I'm not exactly sure what I'm missing, when I use the dev tools the form shows up properly in the html but the only value that is not being submitted it the one in the drop down.
I looked at my database and it's not submitting any value at all what am I doing wrong, I posted my code below.
******************the form********************
= 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_id, options_for_select( #categories_options),{prompt: "Select a category"}
.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'
******************Controller******************
class MenuPricesController < ApplicationController
before_action :set_menu_price, only: [:show, :edit, :update, :destroy]
def index
#menu_prices = MenuPrice.all
end
def show
#categories = Category.all
end
def new
#menu_price = MenuPrice.new
#categories_options = Category.all.map{|u| [ u.name, u.id ] }
end
def edit
#categories_options = Category.all.map{|u| [ u.name, u.id ] }
end
def create
#menu_price = MenuPrice.new(menu_price_params)
respond_to do |format|
if #menu_price.save
format.html { redirect_to #menu_price, notice: 'Menu price was successfully created.' }
format.json { render :show, status: :created, location: #menu_price }
else
format.html { render :new }
format.json { render json: #menu_price.errors, status: :unprocessable_entity }
end
end
end
def update
respond_to do |format|
if #menu_price.update(menu_price_params)
format.html { redirect_to #menu_price, notice: 'Menu price was successfully updated.' }
format.json { render :show, status: :ok, location: #menu_price }
else
format.html { render :edit }
format.json { render json: #menu_price.errors, status: :unprocessable_entity }
end
end
end
def destroy
#menu_price.destroy
respond_to do |format|
format.html { redirect_to menu_prices_url, notice: 'Menu price was successfully destroyed.' }
format.json { head :no_content }
end
end
private
def set_menu_price
#menu_price = MenuPrice.find(params[:id])
end
def menu_price_params
params.require(:menu_price).permit(:category, :price, :description, :serves)
end
end
You need to whitelist category_id not category.Change your menu_price_params to
def menu_price_params
params.require(:menu_price).permit(:category_id, :price, :description, :serves)
end
In your view you have
= f.select :category_id
while in your MenuPricesController you have
params.require(:menu_price).permit(:category, ..)
Just change the :category to :category_id