i need update a single record attribute but i can´t. alumno_id is foreign key of model 'alumno'. the code show the records and if submit 'Aceptar' in one record, need a change the attribute estado to 1
in Model
class Postulacion < ActiveRecord::Base
attr_accessible :ramo, :estado, :alumno_id
belongs_to :alumno
end
in View
<h1>Lista de Postulaciones</h1>
<% #postulaciones.each do |p| %>
<% #id = p.id %>
<%= #id %>
<p>
<td><%= Alumno.find(p.alumno_id).full_name%></td>
<td><%='=> '+ p.ramo %></td>
<td><% if p.estado == 0 %>
<%= 'Pendiente =>' %>
<%= form_tag :action => 'aceptar' do %>
<%= submit_tag 'Aceptar' %></p>
<%end%>
<%else%>
<%='=> Aceptado' %>
<%end%>
</td>
</p>
<% end %>
in controller
class ListadoController < ApplicationController
def listar
#postulaciones = Postulacion.all
respond_to do |format|
format.html
format.json { render json: #postulaciones }
end
end
def aceptar
#postulacion = Postulacion.where(id: #id).first #Edit
#postulacion.estado = 1 #Edit
#postulacion.save #Edit
redirect_to "/"
end
end
Error "undefined method `update_attribute' for []:ActiveRecord::Relation"
Thanks
With this code:
#postulacion = Postulacion.where(alumno_id: #id )
You are declaring #postulacion as a collection, not as a single instance. You can fix this by calling .first:
#postulacion = Postulacion.where(alumno_id: #id ).first
Or by using find_by instead of where:
#postulacion = Postulacion.find_by(alumno_id: #id )
One other thing - this code isn't checking for the possibility that the Postulacion instance might not exist. You should add some logic to handle this...
Your #postulacion variable holds ActiveRecord::Relation instead of single ActiveRecord object. Try:
def acceptar
#postulacion = Postulacion.find_by_alumino_id(#id)
# ...
end
or, if you'd be using Rails 4:
#postulacion = Postulacion.find_by(alumino_id: #id)
Related
I try to pass 2 options for search. First [:q] for input text by visitor and another one from model camping "nomdep" (like departement in english). When i try to search by input it's works, but since i try to add select_tag i have an error
ERROR
undefined method `map' for nil:NilClass
I m lost, do u have any ideas ?
Sorry for my english, i m french.
Home_controler.rb
def index
if params[:q].nil?
"Entrez un mot clef"
else
#campings = Camping.__elasticsearch__.search params[:q,:nomdep]
#camping = Camping.all
end
end
def result
if params[:q].nil?
#campings = []
else
#campings = Camping.__elasticsearch__.search(params[:q]).page(params[:page]).per(14).results
end
end
View
<div class="search">
<%= form_tag(result_path, method: :get) %>
<%= text_field_tag :q, params[:q], class:"search-query form-control" %>
<%= select_tag(:nomdep, options_for_select(#camping)) %>
<%= submit_tag "Partez", class:"btn btn-danger", name: nil %>
</div>
EDIT
Now i dont have any error but the search dont work if [:q] empty. So if i only select_tag => no result.
How fix this ?
My full home_controller.rb
class HomeController < ApplicationController
def index
#camping = Camping.all
if params[:q].nil?
"Entrez un mot clef"
else
#campings = Camping.__elasticsearch__.search params[:q, :nomdep]
end
end
def result
if params[:q].nil?
#campings = []
else
#campings = Camping.__elasticsearch__.search(params[:q]).page(params[:page]).per(14).results
end
end
end
my view
<div class="search">
<%= form_tag(result_path, method: :get) %>
<%= select_tag :nomdep, options_from_collection_for_select(#camping, :id, :nomdep), prompt: "Département" %>
<%= text_field_tag :q, params[:q], class:"search-query form-control" %>
<%= submit_tag "Partez", class:"btn btn-danger", name: nil %>
</div>
#camping = Camping.all
This variable will be nil unless :q was passed in params to index action. options_for_select(#camping) will attempt to call #map on this variable and raise error when it is not initialized.
You should make sure it is initialized. For example, try rewriting your action:
def index
#camping = Camping.all
if params[:q].nil?
"Entrez un mot clef"
else
#campings = Camping.__elasticsearch__.search params[:q]
end
end
I want to say a big big big THANKS to #Baradzed ! We talked yesterday and he find a solution thats work perfectly !
home_controller.rb
class HomeController < ApplicationController
def index
#camping = Departement.all
if params[:q].blank? || params[:nomdep].blank?
#campings = Camping.__elasticsearch__.search params[:nomdep]
else
#campings = Camping.__elasticsearch__.search params[:q]
end
end
def result
querystring = params.slice(:nomdep, :other_param, :any_params_except_q_because_we_will_process_q_separately)
.select{|k,v| v.present?}
.map {|key, value| "#{key}:\"#{value.gsub(/([#{Regexp.escape('\\+-&|!(){}[]^~*?:/')}])/, '\\\\\1') }\""}
.join(" AND ")
freetext = params[:q]
freetext.gsub!(/([#{Regexp.escape('\\+-&|!(){}[]^~*?:/')}])/, '\\\\\1')
querystring = ["*#{freetext}*",querystring].select{|v| v.present?}.join(" AND ") if params[:q].present?
if querystring.blank?
flash[:notice] = "Aucune mots clefs"
redirect_to action: :index and return
else
#campings = Camping.__elasticsearch__.search(
query: { query_string: {
query: querystring
}}).page(params[:page]).per(14).results
end
#hash = Gmaps4rails.build_markers(#campings) do |camping, marker|
marker.lat camping.latitude
marker.lng camping.longitude
marker.infowindow render_to_string(:partial => "/campings/infowindow", :locals => { :camping => camping})
marker.picture ({
"url" => "http://avantjetaisriche.com/map-pin.png",
"width" => 29,
"height" => 32})
end
end
end
view
<div class="search">
<%= form_tag(result_path, method: :get) %>
<%= select_tag :nomdep, options_from_collection_for_select(#camping, :nomdep, :nomdep), prompt: "Département" %>
<%= text_field_tag :q, params[:q], class:"search-query form-control" %>
<%= submit_tag "Partez", class:"btn btn-danger", name: nil %>
Been struggling with this query for a few days. I have 3 models Books, Children and Hires. I have created a view for hires which allows a user to select 2 books and a single child and what i'm looking to do is insert two rows to reflect this into the 'hires' table. I have some JS that populates the hidden fields with the values that they require. Now, I don't think nested attributes is the way to go, because i'm trying to insert directly into the joining table.
So, what i'm trying now is the following:
hires/_form.html.erb
<%= form_for(#hire) do |f| %>
<% 2.times do %>
<%= f.hidden_field :child_id %>
<%= f.hidden_field :book_id %>
<% end %>
<%= f.submit 'Take me home' %>
<% end %>
and then what I want to do is to run through the 'create' function twice in my controller and thus create two rows in the 'hires' model. Something like this:
hires_controller.rb
def create
hire_params.each do |hire_params|
#hire = Hire.new(hire_params)
end
end
Is this completely the wrong way to go? I'm looking for advice on the right way to do this? If this will work, what's the best way to format the create statement?
** Edit **
I have 3 models. Each Child can have 2 books. These are my associations:
class Child < ActiveRecord::Base
has_many :hires
has_many :books, through: :hires
end
class Hire < ActiveRecord::Base
belongs_to :book
belongs_to :child
accepts_nested_attributes_for :book
accepts_nested_attributes_for :child
end
class Book < ActiveRecord::Base
has_many :hires
has_many :children, through: :hires
belongs_to :genres
end
hires/new.html.erb
<div class="form-inline">
<div class="form-group">
<h1><label for="genre_genre_id">Pick Book 1:
<%=collection_select(:genre1, :genre_id, #genres.all, :id, :Name, {prompt: true}, {:class => "form-control dropdown"})%></label></h1>
</div>
</div>
<div id="book1-carousel" class="owl-carousel owl-theme">
<% #books.each do |book| %>
<div data-id = "<%= book.id %>" class="tapbook1 tiles <% #genres.each do |g|%> <% if g.id == book.Genre_id %> book1genre<%=g.id %> <% end end%> <%= %>"><a class="item link"><% if book.bookimg.exists? %><%= image_tag book.bookimg.url(:small), :class => "lazyOwl", :data => { :src => book.bookimg.url(:small)}%> <%end%></br><p class="tile_title" ><%= book.Title %></p></a></div>
<% end %>
</div>
<div class="form-inline">
<div class="form-group">
<h1><label for="genre_genre_id">Pick Book 2:
<%=collection_select(:genre2, :genre_id, #genres.all, :Name, :Name, {prompt: true}, {:class => "form-control dropdown"})%></label></h1>
</div>
</div>
<div id="book2-carousel" class="owl-carousel owl-theme">
<% #books.each do |book| %>
<div data-id = "<%= book.id %>" id="<%= book.id %>" class="tapbook2 tiles <% #genres.each do |g|%> <% if g.id == book.Genre_id %> book2genre<%=g.id %> <% end end%> <%= %>"><a class="item link"><% if book.bookimg.exists? %><%= image_tag book.bookimg.url(:small) , :class => "lazyOwl", :data => { :src => book.bookimg.url(:small)}%> <%end%></br> <p class="tile_title"><%= book.Title %></p></a></div>
<% end %>
</div>
<h1 class="child_heading1" >Now choose your name:</h1>
<div id="children-carousel" class="owl-carousel owl-theme">
<% #children.each do |child| %>
<div data-id = "<%= child.id %>" class="tapchild tiles"><a class="item link"><% if child.childimg.exists? %><%= image_tag child.childimg.url(:small), :class => "lazyOwl", :data => { :src => child.childimg.url(:small)} %> <%end%></br> <p class="tile_title"><%= child.nickname %></p></a></div>
<% end %>
</div>
<%= render 'form' %>
and the coffeescript:
hires.coffee
$(document).on 'ready page:load', ->
book1carousel = $("#book1-carousel")
book2carousel = $('#book2-carousel')
book1carousel.owlCarousel items: 5, lazyLoad : true
book2carousel .owlCarousel items: 5, lazyLoad : true
$('#children-carousel').owlCarousel items: 5, lazyLoad : true
book1clickcounter = 0
book2clickcounter = 0
childclickcounter = 0
book1selection = 0
book2selection = 0
$('.tapbook1').on 'click', (event) ->
$this = $(this)
book1id = $this.data('id')
book1selection = book1id
if $this.hasClass('bookclicked')
$this.removeAttr('style').removeClass 'bookclicked'
book1clickcounter = 0
$('#hire_book_id').val("");
book1selection = 0
else if book1clickcounter == 1
alert 'Choose one book from this row'
else if book1selection == book2selection
alert "You've already picked this book"
else
$('#hire_book_id').val(book1id);
$this.css('border-color', 'blue').addClass 'bookclicked'
book1clickcounter = 1
return
$('.tapbook2').on 'click', (event) ->
$this = $(this)
book2id = $this.data('id')
book2selection = book2id
if $this.hasClass('book2clicked')
$this.removeAttr('style').removeClass 'book2clicked'
book2clickcounter = 0
book1selection = 0
else if book2clickcounter == 1
alert 'Choose one book from this row'
else if book1selection == book2selection
alert "You've already picked this book"
else
$this.css('border-color', 'blue').addClass 'book2clicked'
book2clickcounter = 1
return
$('.tapchild').on 'click', (event) ->
$this = $(this)
childid = $this.data('id')
if $this.hasClass('childclicked')
$this.removeAttr('style').removeClass 'childclicked'
childclickcounter = 0
$('#hire_child_id').val("");
else if childclickcounter == 1
alert 'Choose one child from this row'
else
$this.css('border-color', 'blue').addClass 'childclicked'
childclickcounter = 1
$('#hire_child_id').val(childid);
return
jQuery ($) ->
$('td[data-link]').click ->
window.location = #dataset.link
return
return
return
My approach to this would be what's called a form object, a class that acts like a model but exists only to handle the creation of multiple objects. It provides granular control, but at the expense of duplicating validations. In my opinion (and that of many others), it's a much better option than nested attributes in most cases.
Here's an example. Note that I don't have any idea what your application does, and I didn't look at your associations close enough to make them accurate in this example. Hopefully you'll get the general idea:
class HireWithBookAndChild
include ActiveModel::Model
attr_accessor :child_1_id, :child_2_id, :book_id
validates :child_1_id, presence: true
validates :child_2_id, presence: true
validates :book_id, presence: true
def save
if valid?
#hire = Hire.new(hire_params)
#child_1 = #hire.child.create(id: params[:child_1_id])
#child_2 = #hire.child.create(id: params[:child_2_id])
#book = #hire.book.create(id: params[:book_id])
end
end
end
By including AR::Model, you get validations and an object you can create a form with. You can even go into your i18n file and configure the validation errors messages for this object. Like an ActiveRecord model, the save method is automatically wrapped in a transaction so you won't have orphaned objects if one of them fails to persist.
Your controller will look like this:
class HireWithBookAndChildController < ApplicationController
def new
#hire = HireWithBookAndChild.new
end
def create
#hire = HireWithBookAndChild.new(form_params)
if #hire.save
flash['success'] = "Yay"
redirect_to somewhere
else
render 'new'
end
end
private
def form_params
params.require(:hire_with_book_and_child).permit(:child_1_id, :child_2_id, :book_id)
end
end
Your form will look like this:
form_for #hire do |f|
f.hidden_field :child_1_id
...
f.submit
end
You'll notice right away that everything is flat, and you aren't having to mess with fields_for and nested nested parameters like this:
params[:child][:id]
You'll find that form objects make your code much easier to understand. If you have different combinations of children, books and hires that you need to create, just make a custom form object for each one.
Update
A solution that might be more simple in this case is to extract a service object:
class TwoHiresWithChildAndBook < Struct.new(:hire_params)
def generate
2.times do
Hire.create!(hire_params)
end
end
end
And from your controller:
class HiresController
def create
generator = HireWitHChildAndBook.new(hire_params)
if generator.generate
*some behavior*
else
render :new
end
end
end
This encapulates the knowledge of how to create a hire in one place. There's more detail in my answer here: Rails 4 Create Associated Object on Save
I'm using Rails3 to build a simple customer information page (in table format). On this page user can edit each customer's detailed information. It's possible for each customer to have multiple records. I use link_to to get to the edit page:
<td class="edit" id="edit">edit
<%= link_to 'edit', :action => :edit, :cust_id => ci.cust_id %>
</td>
edit.html.erb:
<h1>Editing cust</h1>
<%= form_for(#cust_info) do |cust| %>
Customer: <%= cust.text_field :cust_schema %>
<%= cust.submit "Save" %>
<% end%>
In my controller, I have this:
def edit
cust_id = params[:cust_id]
#cust_info = CustInfo.find(:all, :conditions => ["cust_id = ?", cust_id])
end
The customer info page shows right. When I click the edit link, I got the error message:
ActionView::Template::Error (undefined method `cust_info_cust_info_path' for #<#<Class:0x7fb0857ce7b8>:0x7fb0857ca780>):
1: <h1>Editing cust</h1>
2:
3: <%= form_for(#cust_info) do |cust| %>
4: Customer: <%= cust.text_field :cust_schema %>
5: <%= cust.submit "Save" %>
6: <% end%>
app/views/track/edit.html.erb:3:in `_app_views_track_edit_html_erb___102324197_70198065248580_0'
Where does `cust_info_cust_info_path' come from?
EDIT: here is the code in the controller:
class TrackController < ApplicationController
def display
end
def information
end
def customerinfo
#cust_info = CustInfo.find(:all, :order=>"cust_id")
#cust_info.each do |ci|
if ci.upload_freq == 'W'
ci.upload_freq = 'Weekly'
elsif ci.upload_freq == 'M'
ci.upload_freq = 'Monthly'
end
end
end
def edit
cust_id = params[:cust_id]
#cust_info = CustInfo.find(:all, :conditions => ["cust_id = ?", cust_id])
end
end
end
Change #cust_info = CustInfo.find(:all, :conditions => ["cust_id = ?", cust_id])
to
#cust_info = CustInfo.find(cust_id)
I have form that create two objects and save them to database.
I want to do next things:
save data in database (booth objects)
validate fields (I have validation in model)
and if validation fail, I want to populate fields with entered data
edit action for this form
Problems:
If I use #report I get:
Called id for nil, which would
mistakenly be 4 error
(can't find object). I have in controller, in encreate action #report = ReportMain.new and in action that render that view.
When I use :report_main (model name) it works, it save data to database, but I can't get fields populated when validation fails.
Questions:
What to do with this two models to make this to work (validation, populating fields, edit)?
Can you give me some advice if approach is wrong?
My view looks like this:
<%= form_for(#report, :url => {:action => 'encreate'}) do |f| %>
<%= render "shared/error_messages", :target => #report %>
<%= f.text_field(:amount) %>
<% fields_for #reporte do |r| %>
<%= r.check_box(:q_pripadnost) %>Pripadnost Q listi
<%= select_tag('nacinpakovanja',options_for_select([['Drveno bure', 'Drveno bure'], ['Kanister', 'Kanister'], ['Sanduk', 'Sanduk'], ['Kese', 'Kese'], ['Posude pod pritiskom', 'Posude pod pritiskom'], ['Kompozitno pakovanje', 'Kompozitno pakovanje'], ['Rasuto', 'Rasuto'], ['Ostalo', 'Ostalo']])) %>
<%= r.text_field(:ispitivanjebroj) %>
<%= r.text_field(:datumispitivanja) %>
<% end %>
<input id="datenow" name="datenow" size="30" type="text" value="<%= #date %>">
<div class="form-buttons">
<%= submit_tag("Unesi izvestaj") %>
</div>
<% end %>
encreate actin in ReportController:
def encreate
#report = ReportMain.new
#reporte = ReportE.new
#reportparam = params[:report_main]
#report.waste_id = params[:waste][:code]
#report.warehouse_id = Warehouse.find_by_user_id(current_user.id).id
#report.user_id = current_user.id
#report.company_id = current_user.company_id
#report.amount = #reportparam[:amount]
#report.isimport = false
#report.isfinished = false
#report.reportnumber = ReportMain.where(:company_id => current_user.company_id, :isimport => false).count.to_i+1
if #report.save
#reporte.report_main_id = #report.id
else
redirect_to(:action => 'exportnew')
return
end
#reporte.vrstaotpada = params[:vrstaotpada]
#reporte.nacinpakovanja = params[:nacinpakovanja]
#reporte.ispitivanjebroj = #reportparam[:ispitivanjebroj]
#reporte.datumispitivanja = #reportparam[:datumispitivanja]
#reporte.q_pripadnost = #reportparam[:q_pripadnost]
#reporte.datumpredaje = #date
if #reporte.save
redirect_to(:action => 'show', :id => #reporte.id)
else
redirect_to(:action => 'exportnew')
end
end
I think your problem in this case is that you use redirect_to instead of render. When you use redirect_to then you lose all the variables from your current action. I would probably do something like this in your encreate action:
if #reporte.save
render :show
else
render :exportnew
end
When you use render then it will use the variables from the current action but the view from the action you send to the render method. So when form_for is called with the #report variable, it is already populated with the values that was sent to encreate. Just make sure that you use the same variable names in the different actions but it looks like you do that already.
I have the following problem. I have a form which takes input for a "Chart" object. But after processing the form, i wish to display one of the values, and it adds the key of this value.
Class model
class Chart
attr_accessor :title, :series
def initialize(title = nil, series = [])
#title, #series = title, series
end
end
View of form:
<% form_for :chart , :url => { :action => "show" } do |f| %>
<p>
<%= f.label :title %><br />
<%= f.text_field :title %>
</p>...
<% end %>
Chart controller, show method:
def show
#chart = Chart.new(params[:chart])
end
View of show:
<h2><%=h #chart.title %></h2>
Which displays: "title"input_forms_title""
for example: writing in the input form: Economy, prints in the show view: "titleEconomy"
Any ideas?
I have just figured it out. The problem was in the constructor or initialize method. By changing the initialize method to:
def initialize( options = {} )
#title = options[:title]
#series = []
end
It now accepts all params perfectly!