I'm trying to do that:
User upload file in first controller,
In some conditions I show page to user for choose element from file and pass file data to another controller in params: data#new
In data#new:
#elm_file = Rails.cache.read(params[:cache_id])
#elm_id = params[:index]
#user_name = params[:name]
new_elm_id = Elm.create_from_file #elm_file, #elm_id, #user_name
if new_elm_id != 0
redirect_to :action => '', :id => new_elm_id
end
return
in Model:
new_elm = Elm.new
return new_elm.id
The problem is - nothing returned. How can I record new element to database?
Your new action of the controller data returns nothing, because you haven't defined anything behind the return argument.
The two other lines, which are supposed to be from your model, returns nothing, because the id field is only set for persisted records. You maybe want to persist it with create().
Related
I have a problem for redirecting back after an action.
My condition is this:
Client, Volunteer, and staff has many next of kin. After creating a new next of kin, I want to redirect back to edit page of a particular client/volunteer/staff.
my current solution is this.
For the link to add
<%= link_to new_admin_people_next_of_kin_path(source: source,
source_id: source_id),
class: 'js-btn-add btn btn-success btn-sm' do %>
Add New Next of Kin
<% end %>
where
source = :client/:staff/:volunteer
source_id = id(primary key) or the staff/volunteer/client
my new method
def new
#person = Person.new
#person.source = params[:source]
#person.source_id = params[:source_id]
end
later I will pass source and source_id as hidden parameter.
my people_controller create method(because next of kin is a person)
def create
if params[:source] == 'client'
#client = Client.find(params[:source_id])
#pnok = #client.people_next_of_kin.build
elsif params[:source] == 'volunteer'
#volunteer = Volunteer.find(params[:source_id])
#pnok = #volunteer.people_next_of_kin.build
elsif params[:source] == 'staff'
#staff = Staff.find(params[:source_id])
#pnok = #staff.people_next_of_kin.build
else
#pnok = PeopleNextOfKin.new
end
#person = #pnok.build_next_of_kin
Person.transaction do
#person.update_attributes(create_params)
#person.save(validate: false)
end
end
as you can see, it's not really clean and hardcoded. I have read on polymorphic path, but I can't really find a way to use that for my solution as I need to build a new next of kin first and I cannot pass in an object in link_to or redirect_to, and then there's also a problem whereby the next of kin is not saved yet in database, so I cannot use person.find.
any solution?
It's a little tough to see what you are after from your example. I would guess that you want to redirect back to the staff / volunteer / client page and there would be a Parent / Child relationship with a NOK.
However, it's unclear what your models look like. For example, you might be using single table inheritance and polymorphism because these are all "People", or you might have the relationships in your models. I think the solution depends on which path you take.
For example, you might use something like this:
def Client
has_many :noks
end
If you had that, you could build the empty :nok record and then redirect back to the :client, and let the Rails / ActiveRecord internals manage the relationship. For example, the Client #show page may have places to list all Next of Kins that enumerates all of the kin.
Summary: I think you are trying to do too much in your controller without using models the way that RoR supports.
I created a model for a thing called a Lesson that has :content and a :user_id. For early builds of this app, I want the content to be changing, based on my entry, and for the user_id to always = 1 so that it's clean in the DB and there's not a nil value.
How do I go about this?
In my lessons_controller.rb I have this:
def create
#lesson = Lesson.new(params[:lesson])
if #lesson.save
... do something
else
... do something else
I'm guessing this would be the best place to define that the user_id = 1 but how should I go about that?
You can just set #lesson.user_id = 1 in the line after you create it with new, and before you save it.
Another way to do it would be to set a hook in the lesson model -
before_validation :on => :create do |lesson|
lesson.user_id = 1
end
I am looking for a clean solution to create multiple database records from a single form, that all have the same values specified in the form. Only the ID should obviously be different.
I need this function to let the user create 100+ records at once as a kind of templating.
So ideally in the form the user can type a number for the count of records she/he would like to create with the filled in values.
Use an iterator. Example:
def create_many
count = params[:count].to_i
# count within reasonable limits, check if object will validate
if (1..100) === count && Object.new(params[:object]).valid?
count.times { Object.create(params[:object]) } # <= the iterator
redirect_to my_custom_view # <= custom 'show' view
else
render :text => "Couldn't do it." # <= failure message
end
end
This example expects two parameters, :object which contains resource attributes, and :count which specifies how many records to create.
You need a custom show view to handle getting and displaying all of the newly created records.
I have three models, booking, room and travellers.
Booking has many rooms
room has many travellers
Since I'm doing a multi-step wizard booking and rooms gets created first, the travellers are created later in the update action.
This is the log for the update action: http://pastie.org/private/it7onlg8bnurqkgv6mptrq
And this is the relevant methods and actions for creating the travellers:
The view action
def step3
#booking = Booking.find_by_random_url_key(params[:id])
#variant = #booking.variant
#booking.rooms.collect {|room| room.number_of_persons.times {room.travellers.build} if room.travellers.blank?}
render :partial => "bookings/partials/step3", :layout => "booking"
end
room.number_of_persons method just return an int.
Relevant part of the update action
..
elsif #booking.update_attributes(params[:booking]) && #booking.aasm_state == "step3"
redirect_to booking_step4_url(#booking)
#booking.next!
..
next! is just a aasm transition
If I do a create in the console
Room.last.travellers.create(:forename => "john", :country_name => "Germany")
Only one object is created and even if I go back in the view and submit again he correctly updates the created object and does not create new ones.
#booking.rooms.collect {|room| room.number_of_persons.times {room.travellers.build} if room.travellers.blank?}
This looks wrong to me. You're initiating travellers but not storing them and collecting an array but not doing anything with it. Also, I understand you want to create a number of travellers but you condition on travellers being blank.
#travellers = #booking.rooms.collect { |room| room.number_of_persons.times { room.travellers.build } }
I got this to work by doing a create in the model instead of doing it through the forms.
So basically after the rooms are created I do:
self.rooms.map {|r| r.number_of_persons.times {r.travellers.create}}
I have controller with action new, and I want it to create ActiveRecord::Base descendant object, and write it into database (without showing it to user).
def new
active_order = current_user.orders.find {|o| o.status > 0 }
active_order = Order.new if active_order.nil?
(...)
end
Order.new creates local object, but my question is -- how to make Rails to fill it with default values and write to database?
You can write an unsaved ActiveRecord object instance to the database with the save method:
active_order = Order.new if active_order.nil?
active_order.save
It won't fill in the columns automatically, however. If you want to populate it with default values you can do this before calling save:
active_order = Order.new if active_order.nil?
active_order.field_name = "foo"
active_order.save
Or you can pass it in when you call new:
active_order = Order.new(:field_name => "foo") if active_order.nil?
active_order.save
If you want to do something fancier, you can have Rails automatically populate fields when you save by adding something like this to the model:
before_validation_on_create :set_default_values
def set_default_values
field_name = "foo" if field_name.blank?
end
you can use Order.Create(...) which will create a new object and persist it in the database (assuming Order is a child of ActiveBase of course)