I have a model called event which attributes are:
string "name"
string "location"
string "lecturer"
date "start_time"
date "end_time"`
I want to take data from icalendar type file and create event instances. How should I do this ? I tried to do a method in events_controller.rb:
def new_method
#ievent_file = File.open("calendar2.ics")
#ievents = Icalendar::Event.parse(#ievent_file)
#ievent = #ievents.first
#ievent = Event.new(name:#ievent.summary,location:#ievent.location, lecturer:#ievent.description, start_time:#ievent.dtstart, end_time:#ievent.dtend)
end
But then what I should do with it ? Should I call this function in view or maybe should I take this code to method called create which looks like this:
def create
#event = Event.new(event_params)
respond_to do |format|
if #event.save
format.html { redirect_to #event, notice: 'Event was successfully created.' }
format.json { render :show, status: :created, location: #event }
else
format.html { render :new }
format.json { render json: #event.errors, status: :unprocessable_entity }
end
end
end
my understanding calendar2.ics have many records, if you want to loop through all the event inside calendar2.ics and save it to your event table (import ics file to event table)
below are sample steps, inside your routes file create one method
resources :events do
collection {
get :transfer_data_from_ics
}
end
inside your events_controller you create 2 methods
def transfer_data_from_ics
# get data from ics
#ievent_file = File.open("calendar2.ics")
#ievents = Icalendar::Event.parse(#ievent_file)
# loop through
#ievents.each do |i_event|
Event.create(
name: i_event.summary,
location: i_event.location,
lecturer: i_event.description,
start_time: i_event.dtstart,
end_time: i_event.dtend)
end
# route back to events list
redirect_to events_path
end
to get the method called you can create menu / button with link_to as follow:
<%= link_to "Transfer data", transfer_data_from_ics_events_path %>
Related
I got a simple app where users can create projects and timetrackers which belong_to the projects and are basically timestamps. timetrackers have a start_time and an end_time(both :datetime), now i want to calulate the duration between the two values and save it into timespan which is :float.
for this i got a set_timespan action in my timetrackers_controller
def set_timespan
#job = Job.find(params[:job_id])
#timetracker = Timetracker.find(params[:id])
#timetracker.timespan = (#timetracker.end_time - #timetracker.start_time).round / 3600
end
The Create action
def create
#job = Job.find(params[:job_id])
#timetrackers = #job.timetrackers.new(timetracker_params)
#timetrackers.user_id = current_user.id
#timetrackers.job_id = #job.id
#set_timespan
respond_to do |format|
if #timetrackers.save
format.html { redirect_to #job, notice: 'Timestamps created successfully.' }
format.json { render :show, status: :created, location: #job }
else
format.html { redirect_to new_timetracker_path, notice: "Please fill out the form." }
format.json { render json: #job.errors, status: :unprocessable_entity }
end
end
end
when i try to shoot the action in my create action just before #timetrackers.save, i get a Couldn't find Timetracker without an ID Error. Also I get redirected to jobs/3/timetrackers. Why is the ID not found and how can i properly trigger an action in my controller to calculate the timespan? Later i want to sum up the timespans.
You'll still have access to the #timetrackers instance variable, so as a simple solution:
def set_timespan
#job = Job.find(params[:job_id])
#timetrackers.timespan = (#timetracker.end_time - #timetracker.start_time).round / 3600
end
I'd take this a step further and remove the method altogether, as #job is also available and just use the pertinent line directly in the create action:
def create
# ...
#timetrackers.job_id = #job.id
# v here v
#timetrackers.timespan = (#timetrackers.end_time - #timetrackers.start_time).round / 3600
respond_to do |format|
# ...
end
As a final, perhaps ideal solution, you can use a before_create callback in your Timespan model:
# timespan.rb
before_create -> { self.timespan = (end_time - start_time).round / 3600 }
That way, your timespan will be set automatically as it's created.
I realize you have an answer you already like, but...
Another approach would be to groom your timetracker_params so that they include all the appropriate data using a method like new_timetracker_attributes. Something, perhaps, like:
def create
#job = Job.find(params[:job_id])
#timetrackers = #job.timetrackers.new(new_timetracker_attributes)
respond_to do |format|
if #timetrackers.save
format.html { redirect_to #job, notice: 'Timestamps created successfully.' }
format.json { render :show, status: :created, location: #job }
else
format.html { redirect_to new_timetracker_path, notice: "Please fill out the form." }
format.json { render json: #job.errors, status: :unprocessable_entity }
end
end
end
private
def new_timetracker_attributes
timetracker_params.merge(
user_id: current_user.id,
timespan: ((end_time-start_time).round/3600)
)
end
def timetracker_params
params.require(:timetracker).permit(:start_time, :end_time)
end
def start_time
timetracker_params[:start_time]
end
def end_time
timetracker_params[:end_time]
end
There are many ways you could groom your timetracker_params and this is just one idea.
The point is, you have all of your new instance attribute set up going on in one place instead of smeared in various places across your application. IMO, it makes it a wee bit easier to understand what is going on and debug if things go pear shaped.
I have an application with two means of inputting data: (1) a single-entry page / a form_with fields [ aka 'input_page' ] and (2) a file upload page [ aka 'file_upload_page' ] that accepts a spreadsheet with multiple entries (here, student courses).
My goal is to have the validation error messages appear on the view associated with the source of input, either the input_page or the file_upload_page.
The courses controller currently looks like this:
def create
#user = current_user
#course = (Course.import(params[:course][:file]) ||
Course.new(course_params))
# the input is either a file (spreadsheet) or the aforementioned
# `form_with` fields
#course.save
respond_to do |format|
if #course.save
# when successful, both inputs return the same view,
# `courses_path`
format.html { redirect_to courses_path, notice: '...success!' }
format.json { render :show, status: :created, location:
courses_path }
else
# here is where the 'challenge' arises for the single input_page
format.html { redirect_to input_page, alert:
course.errors.full_messages }
# now, how do I *conditionally* return the file_upload_page if
# the user uploaded multiple courses with a spreadsheet
format.html { redirect_to file_upload_page, alert:
course.errors.full_messages }
end
(The uploaded spreadsheet file is parsed using the Roo gem in the courses model, courses are saved, and returned to the courses controller, create action.)
Currently, (1) a successful save of either the input_page or the file_upload_page - correctly - returns the courses_path. (2) If validations fail, both the input_page and the file_upload_page return the input_page view - because that code is run first.
I need something in the else block like 'if input is from X view, return X view with errors, else return Z view with errors'
Your params tell you if it's a file upload or not so use that logic to determine the errors path:
def create
#user = current_user
#course = Course.import(params[:course][:file]) || Course.new(course_params)
if #course.save
respond_to do |format|
format.html { redirect_to courses_path, notice: '...success!' }
format.json { render :show, status: :created, location: courses_path }
end
else
errors_path = params[:course][:file] ? file_upload_page : input_page
respond_to do |format|
format.html { redirect_to errors_path, alert: course.errors.full_messages }
end
end
end
I want to create multiples objects of a same model in Rails and I'm facing some problems saving them. I already add and remove fields dynamically, but I can't figure out how to save the multiples objects.
I'm receiving the data from my View like this:
Parameters: {
"utf8"=>"✓",
"authenticity_token"=>"0aoRgalvZPKdBJr15EooxNCimh2C6R2RBYi3wTXTpaIwpzb8cNSAH/968932KFscg8eiNPej1x2iYFsaWalVQw==",
"transaction"=>{
"client_id"=>"206",
"invoice_id"=>"1",
"date"=>"07/07/2016",
"value"=>"50",
"description"=>""},
"dates"=>[
"07/08/2016",
"07/09/2016"],
"values"=>[
"49",
"48"],
"commit"=>"Save"}
transaction is the main transaction, dates and values are what difers from the main transaction and the other two transactions.
My create method in TransactionController is like this:
def create
#transaction = Transaction.new(transaction_params)
dates = params['dates']
values = params['values']
if(!dates.nil?)
#transactions_ = []
dates.length.times do |i|
t = Trasanction.create(
client_id: #transaction.client_id,
invoice_id: #transaction.invoice_id,
description: #transaction.description,
date: dates[i],
value: values[i])
#transactions_ << t
end
end
respond_to do |format|
if #transaction.save
#transactions_.each do |t|
t.save
end
format.html { redirect_to #transaction, notice: 'Transaction succefully created.' }
format.json { render :show, status: :created, location: #transaction }
else
format.html { render :new }
format.json { render json: #transaction.errors, status: :unprocessable_entity }
end
end
end
But I'm getting this error:
uninitialized constant TransactionsController::Trasanction
t = Trasanction.create(
Apparently I can't call Transaction.create that way, but I'm almost sure I saw something like that on a tutorial.
I see there is a mistake in your class name. It should be
Transaction.create({})
but, you are referring to it as
Trasanction.create({})
Just change the class name and it should work.
I made an AJAX call to send one javascript variable to one method in my controller. My controller looks like this :
def registration
#fund = params[:funds]
#index = params[:indexDecision]
render json: 'ok'
end
def create
#user = User.new(ticket_params)
respond_to do |format|
if #user.save
format.html { redirect_to #user, notice: 'User was successfully created.' }
format.json { render :show, status: :created, location: #user }
Record.create(fund: #funds, weight: #weight)
else
format.html { render :new }
format.json { render json: #user.errors, status: :unprocessable_entity }
end
format.js
end
end
This is my AJAX call :
$.ajax({
url: "/record",
type: "POST",
data: {
funds: funds,
indexDecision: indexDecision
},
complete: function(){
console.log('Congrats');
}
});
And this is my config route file :
resources :users
post '/record' => 'users#registration'
My AJAX call works well. But now I would need the instance variable #fund and #index to be available in the create method. I read that I had to use private method so that the instance variables in the private method would be available in other methods.
I tried but I have an error 400 bad request.
How can I do so that the #funds and #index variables can be available in the create method ?
Your code should probably look like this (I ignored HTML format for simplicity):
def registration
user = User.new(ticket_params)
if user.save
fund = params[:funds]
index = params[:indexDecision]
Record.create(fund: funds, weight: weight)
render json: 'ok'
else
# report error here
end
end
So, for my Rails project I have two models called ButtonOrderDiv and ButtonFinishDiv. They have a has_many/belongs_to relationship where a button_order_div has many button_finish_divs and each button_finish_div belongs to a button_order_div. I am trying to write code so that when the user creates a new button_order_div, the right number of button_finish_divs are automatically created. There is a field for button_order_divs called number_of_parts, which is the number of button_finish_divs to be created. Right now, this is the code that I have inside the ButtonOrderDiv controller:
def create
#button_order_div = ButtonOrderDiv.new(button_order_div_params)
respond_to do |format|
if #button_order_div.save
number = #button_order_div.number_of_parts
for i in number
ButtonFinishDiv.create(button_order_div_id: #button_order_div.id, part: i)
end
format.html { redirect_to #button_order_div, notice: 'Item criado com sucesso.' }
format.json { render :show, status: :created, location: #button_order_div }
else
format.html { render :new }
format.json { render json: #button_order_div.errors, status: :unprocessable_entity }
end
end
end
As you can see, inside the if #button_order_div.save condition, I am trying to create a new ButtonFinishDiv, but it is giving me the "undefined method `each' for 3:Fixnum" error. How do I make this work?
Numbers (Fixnum) don't have the method each (when you do a for x in y, you are trying to iterate through a number), which is specific to the array data structute. What you want is something like this:
1.upto(number) do |i|
ButtonFinishDiv.create(button_order_div_id: #button_order_div.id, part: i)
end