Tricky ruby on rails problem. Does an easy solution exist? - ruby-on-rails

I hope my question is understandable, else I'm glad to clarify.
We have this sport event coming up, and I have the pleasure to register the people. :)
Facts:
one can have a team of 5-10 persons.
Need to know the order in which the people start.
Need to know who the team leader is.
I did a form in the following style:
o [____Write first name here___] <--- this is a textfield
o [____Write second name here__]
o [___________ ... ____________]
...
the "o" is a radio-button, used to pick the team leader.
I have a model Person and a model Team. Every team has a leader_id (which is one of the Person IDs). Furthermore every team :has_many persons.
In the controller I have
def create
#team = Team.new(params[:team])
#team.save #just assume there are no errors
end
In the view I have (for the radio-buttons):
<input id="team_leader_id_**????**"
name="team[leader_id]"
type="radio"
value="**????**"
/>
<input id="team_leader_id_**????**"
name="team[leader_id]"
type="radio"
value="**????**"
/>
# etc.
My question: What should I put at **????** ?
I don't know the IDs of the persons yet, as they haven't been created. I have to put some meta-ID there, which ruby on rails recognizes and links everything correctly?
You don't have to read the rest (it describes the hack I'm using)
As said, at the moment I'm doing an ugly hack: first save the Team (without generating a leader), then fetch the same team from the db, get its people, and find the first person matching the value of
params[:team][:leader_id].
Finally saving this person's ID in the field of leader_id of the team.
But this code is inefficient, huge and buggy, that I suspect there is an easier way.

The radios should have the same name i.e.
<input id="team_persons_attributes_0_leader_id"
name="team[persons_attributes][leader_id]"
type="radio"
value="0"
/>
<input id="team_persons_attributes_1_leader_id"
name="team[persons_attributes][leader_id]"
type="radio"
value="1"
/>
<input id="team_persons_attributes_2_leader_id"
name="team[persons_attributes][leader_id]"
type="radio"
value="2"
/>
This way there can only be one selected (via the browsers internal radio button mechanism) and params[:team][:persons_attributes][:leader_id] will contain an index to params[:team][:persons] which will be the leader's name.
to obtain the id
team = Team.create(params[:team])
params[:team][:persons].each_with_index{|name, idx|
person = Persons.create(:name => name)
#assuming no errors
team.leader_id = person.id if params[:team][:persons_attributes][:leader_id] == idx
}

It seems as though you are submitting a number of users in one go with one of them flagged as the team leader. In this case you could construct something like:
<%= radio_button_tag "[team][leader]","[1]" %>
<%= radio_button_tag "[team][leader]","[2]" %>>
Then in the controller create the people (using nested attributes?), then simply look up the ID of the one flagged as the leader for the team record.

Related

How do I enter race results in my app?

I have three models in my app: Athletes, Races, and Results. An Athlete has many results, a Race has many results, and a Result belongs to an Athlete and a Race. Each race has exactly 12 results.
As a beginning Rails developer, I'm having trouble understanding how to create the web form for entering the 12 race results. Should I maintain Results as a separate resource, or nest them under Races? In my controller, would I create 12 instances of a result object under the New action? How do I submit the appropriate race_id for each instance?
If you could help me clarify my thinking on this problem, and point me in the right direction, it would be greatly appreciated!
You don't need to nest your results if they have unique and auto-generated IDs, but you can if you think it makes you application easier to use or program.
Your web form should probably be based on the use case of entering 12 athletes as they ranked for a single race. That means you could use multiple HTML inputs for each of the results:
<input type="hidden" name="race[results_attributes][][rank]" value="1" />
<input type="text" name="race[results_attributes][][athlete_id]" />
<input type="hidden" name="race[results_attributes][][rank]" value="2" />
<input type="text" name="race[results_attributes][][athlete_id]" />
You could then modify your race model to accept inputs for results:
class Race
has_many :results
accepts_nested_attributes_for :results
end
And simply pass the attributes in an update statement:
Race.find(params[:id]).update_attributes params[:race]
I'm sure there are several ways to approach this. You certainly could nest Results under Races, but then it becomes a question of whether you're creating the Results at the same time as their Race or not (this is worth thinking about because you need to know how to tie your Results to your Race, e.g. does each Result form have a race_id as a hidden field? If so the Race probably needs to already exist). But in either case this would probably be 12 Result forms with Result.new as the object.

How do I create a Up/Down voting system like stackoverflow?

I'm making a site in Rails, and I want to add a vote up/down system like here in Stackoverflow.
Can anyone suggest how to do it? I do know that I'll enter each vote into the database, but I mean, how do I code the vote buttons? What will I use, can anyone help me. Ajax isn't required but it would be nice.
I was going to try to use a POST command and do something like this,
<form name="input" action="/grinders" method="POST">
<input type="hidden" name="id" value="<%=h grinder.id %>">
<input type="hidden" name="vote" value="up">
<input type="submit" value="Vote" />
</form>
But, I get an authenticity token error, and I honestly do not know how to work with the form helper.
Have a votes table like so:
[PK] vote_id, vote_type (up/down), [FK] post_id, [FK] user_id, time [optional]
Also add a score field to your posts table
Then you could have the vote button access a link like: /vote/post_id/type/, eg: /vote/14098/up. This can be done with or without Ajax.
When the vote action is called, check if the user has previously voted on that post - if yes, deny it. If not, create a row with the relevant values in the votes table and update the score field in the posts table.

How do I change the records being displayed on the page with buttons on the page (RoR)

I have a rails app that shows statistics based on an employee's daily production. currently my page shows ALL records.
I know how to show various different combinations such as records made between two dates etc... but what I really would like to do is make it so that single page (say the index page) has 3 controls that allow for it to switch between daily statistic records, weekly statistic records and a custom date constraint of statistic records (such as from date xx/xx/2009 to date xx/xx/2010). I have been searching for a while to attempt to figure this out but I am obviously missing something as I cannot find anyone else who has run into the same issues.
If this is too difficult to do this way, the other - mostly easy way I can see to do this is to create a page for each view, however it still leaves a question on how I set up the control to choose the custom date constraints.
I aplogise in advance for my newbyness but if someone could explain this to me, I think it is going to really increase my understanding of rails. Thanks in advance
Your control can easily append some information to the query string. Like this form does:
<form action="" method="get">
<fieldset>
<button type="submit" name="show" value="daily">Daily stats</button>
<button type="submit" name="show" value="weekly">Weekly stats</button>
</fieldset>
<fieldset>
From <input type="text" name="interval-start" value="" /> till
<input type="text" name="interval-end" value="" />
<button type="submit" name="show" value="interval">Stats for the specified interval</button>
</fieldset>
</form>
When user clicks on some button, browser sends all form fields to the server-side. On the server-side, in your action, you can check for the show property of the params array. Like this:
#reports = case params["show"]
when "daily"
#Just an example. Use ActiveRecord's query interface or Arel in Rails 3, not plain queries
Report.find_by_sql "SELECT * FROM reports WHERE DATE(report_date) = DATE(NOW())"
when "weekly"
Report.find_by_sql "SELECT * FROM reports WHERE WEEK(report_date) = WEEK(NOW())"
when "interval"
Report.find_by_sql "..."
else
#Some other possible values, filters, so on
end
And in your view just output the #report variable as usual.
You could also create a new route for that filtering, maybe /reports/:name, and avoid using forms. In this case, you only create some links that point to the right filter (/reports/daily, /reports/weekly, etc). On the server-side you need to check reports[:name] for the appropriate value.

Rails Dynamic Multi Model Form attributes

This problem has been killing me. I played around with Ryan Bates complex forms, but I can't quite figure out my problem.
I have this schema:
Location has_many :targets
Target has_many :target_classifications
All locations are shown on the page. A user may create a target for any location dynamically through jscript, which then adds a table row under the location 3 selects (that contain available classifications to the target) and a target value. Any number of targets can be created for any location before clicking save.
I'm using rjs to render a target_partial, which has this code:
I'm using fields_for in this way:
for each select. When sumbmitted, I get this hash:
"new_targets"=>
{"7"=>[{"id"=>"13"}, {"id"=>"15"}, {"value"=>"67", "id"=>""}],
"4"=>
[{"id"=>"12"},
{"id"=>"15"},
{"value"=>"23", "id"=>""},
{"id"=>"11"},
{"id"=>"16"},
{"value"=>"67", "id"=>""}]},
So, it separates each target by location ("7" and "4" in this case), but doesn't separate each target. What I want is this:
"new_targets"=>
{"7"=>[
{"target"=>[{"id"=>"13"}, {"id"=>"15"}, {"tonnes"=>"67"}]}
],
"4"=>[
{"target"=>[{"id"=>"12"},{"id"=>"15"},{"tonnes"=>"23"]},
{"target"=>[{"id"=>"11"},{"id"=>"16"},{"tonnes"=>"67"]}
]
}
so I can iterate through each target for each location. I can't seem to add in a new [target] brace in my field_for method (it blows up), but that's kind of what I want to do. Any thoughts?
I don't know if you are doing this, but you need to specify a string instead of the object when using fields_for. I can't see the codes you have in your partial, so I may be way off. Anyway, the way I do it is in a helper:
def fields_for_target(target, &block)
prefix = target.new_record? ? 'new' : 'existing'
fields_for("location[#{prefix}_target_attributes][]", target, &block)
end
This sort of issue is discussed here:
http://wonderfullyflawed.com/2009/02/17/rails-forms-microformat/
But it seems to be a rails 2.3 solution (not an option for me). Basically, I want a form like they've posted on the site:
<input name="creator[widget_attributes][0][id]" />
<input name="creator[widget_attributes][0][name]" />
<input name="creator[widget_attributes][0][price]" />
<input name="creator[widget_attributes][1][id]" />
<input name="creator[widget_attributes][1][name]" />
<input name="creator[widget_attributes][1][price]" />
Just some way to create a unique identifier for each target (or in this case, widget attribute) I want to add. Kind of tough given that a new target is added with jscript. I feel like there should be some way for rails to automatically do this for me
Easy. Look up accepts_nested_attributes_for. :)

Updating Parent/Child Records with model binders in ASP.Net MVC

I have modified the Nerd Dinner application to allow editing of child records by adding the following code to the DinnerForm.ascx
<p>
<%int i = 0;
foreach (NerdDinner.Models.RSVP rsvp in this.Model.Dinner.RSVPs)
{ %>
<%= Html.Hidden("Dinner.RSVPs[" + i + "].RsvpID", rsvp.RsvpID)%>
<%= Html.Hidden("Dinner.RSVPs[" + i + "].DinnerID", rsvp.DinnerID)%>
<%= Html.TextBox("Dinner.RSVPs[" + i + "].AttendeeName", rsvp.AttendeeName)%>
<% i += 1;
} %>
</p>
it is rendering this:
<p>
<input id="Dinner_RSVPs[0]_RsvpID" name="Dinner.RSVPs[0].RsvpID" type="hidden" value="36" />
<input id="Dinner_RSVPs[0]_DinnerID" name="Dinner.RSVPs[0].DinnerID" type="hidden" value="63" />
<input id="Dinner_RSVPs[0]_AttendeeName" name="Dinner.RSVPs[0].AttendeeName" type="text" value="kp" />
<input id="Dinner_RSVPs[1]_RsvpID" name="Dinner.RSVPs[1].RsvpID" type="hidden" value="37" />
<input id="Dinner_RSVPs[1]_DinnerID" name="Dinner.RSVPs[1].DinnerID" type="hidden" value="63" />
<input id="Dinner_RSVPs[1]_AttendeeName" name="Dinner.RSVPs[1].AttendeeName" type="text" value="jim" />
</p>
I have not modified the DinnersControler's Post Edit Action method. The Parent dinner is getting updated as usual, but it appears the UpdateModel(dinner); is not seeing/updating the child RSVP records.
I have tried a few variations on rendering the child records so that the Model binders will see the collection, with no luck.
Is updating parent/child records in one shot by calling UpdateModel(Parent); possible with the current model binders?
I haven't been able to do this myself.
I know that you can update a single child element, ie, Dinner.RSV automatically. I've never seen the ability to update a child enumerable, which would require the binding to know which property is the ID and look for it (ie, Dinner.RSVP.Where(r => r.RSVP_ID == input_id) and then update that). I don't know enough about custom binding to do something like that.
However, what I have done is to do a loop and specify the rsvp and the int as a prefix:
So you do:
UpdateModel("Dinner", Dinner);
to update the parent and then:
int i = 0;
foreach (var r in Dinner.RSVPs) {
UpdateModel(r, "Dinner.RSVPs[" + i++ + "]");
}
Not quite as clean, but it works well for me. It might take a bit more effort to build in validation, though (you want to validate all at the same time, and make sure you don't jump back to the view on the first RSVP with an error).
EDIT: Fixed the code to reflect the OP's solution, including a bug in my parameter order. With that being said, I'm more comfortable using the RSVP.ID property than a running integer. As long as you know that Dinner.RSVPs will be the same on the POST as the GET (I'm confident of this in my code), then using the RSVP.ID will work. Should RSVPs be different, then only those present on both will get updated. However, using the sequential int could potentially cause the wrong object to be updated.
Hope that helps,
James
Ok, so nobody's answering. I don't know the nerddinner app but was interested by your problem. Was hoping to see some answers but, well, none yet. Not 100% sure because of lack of familiarity with ndinner, but could it be related to this post where they mention binding/updating only when a property is explicitly passed?
Your question is whether updating parent/child records in one shot by calling UpdateModel(Parent); possible with the current model binders?
Yes, this is possible. However, it is not possible (without some minor workarounds) if you are using Linq-to-Sql and your child objects are exposed via EntitySet<T> instead of something like IList<T>. I believe this will be (has been?) addressed in the next version of MVC due out with ASP.NET 4.0. For the time being, though, the MVC default model binder does not seem to understand how to work with EntitySet.
Please see this other answer I wrote on a related question some time ago, with details about how I am now dealing with (working around) this situation in certain simple cases. In doing this, I've had to stop worrying so much about how "ideal" this solution is from a DDD/OOP perspective, as a trade-off to simply getting MVC and LTS to play together nicely with minimal effort.
Note, I will admit that James S's solution is probably more "pure," but in order to do this in "one shot" as you ask, you'll need to either wait for ASP.NET 4.0, or use a workaround similar to what you'll find in my other post.
Good luck!

Resources